内存详解(vmmap)

前一篇文章介绍了任务管理器中关于内存的两个重要概念:private和working set。但是内存远不止那么简单,下面我根据VMMap来详细介绍一下内存的分类。

内存是一个很复杂的系统,其中的paging file,sharable memory,reserve和commit等概念使得要算清楚一个进程到底使用了多少内存几乎成了不可能的事情了。

还好我们有VMMap这个工具,它用两个纬度将内存进行了详细的划分。

一个是纵向的纬度,也就是内存是从哪里来的。分为

  1. Image(可执行文件),
  2. Mapped file(由CreateFileMapping以文件作为back up)。
  3. Sharable(由CreateFileMapping以内存作为 back up)
  4. Private Data(由Virtual Alloc分配)
  5. Heap(由new,GlobalAlloc和HeapAlloc等分配)
  6. Stack(栈占用的控件)
  7. Page table(内核里面维护当前虚拟地址控件所需要的内存)
  8. Managed Heap(由.NET garbage collector分配和管理)

               

还有一个横向的维护,分别被称为:

 

  1. Size: 总体大小,包括了commit和没有reservce的内存。如果这项和Committed不 一致,那么就是说有reserve的内存。
  2. Committed: committed的大小,包括Private内存和可共享的内存。
  3. Private:属于当前进程的虚拟内存,指的是当你修改他时仅仅当前进程会受到影响。(copy-on-wirte属性的页面还没被修改时也属于此类)

以上实际上是虚拟内存(virtual memory)的概念,其中的内容可能被物理内存(physical memory)back up,也可能被Paging file back up。

而以下的几个指标指的是物理内存:

  1. Total WS: 所有的working set,包括private working set和sharable working set。
  2. Private WS: private working set。仅属于当前进程的working set。
  3. Sharable WS。可共享的working set。
  4. Shared WS。已经共享的working set,这个值应该是sharable working set的一部分或者全部。

 

为了更具体的了解这几个指标,下面我们根据一些API的具体行为所产生的结果来观察一下他们的含义。

 

New,GlobalAlloc and HeapAlloc:

受影响的是VMMap中的Heap行。

分配时占用的是Committed和Private列,working set不受影响。

当访问时Total working set和Private Working Set跟着上升。

 

VirtualAlloc:

受影响的是VMMap中的Private Data行。

分配Reserve的data时,上升的是第一列Size,第二列Committed不变。

Commit时,上升的是Committed和Private列。Total Working Set列不变。

当访问Commit的内存时,上升的是Total Working set 和Private Working set列。

DeCommit时,只有第一列size保持不变,Committed,Private和Working set列都下降。

Release时,第一列Size也下降。

 

Memory Based CreateFileMapping

这个file mapping不管有没有命名,下面的行为都一样。

受影响的是VMMap中的Sharable行。

调用CreateFileMapping时,不影响任何列,增加的只是系统的Total Commit Charge。

调用MapViewOfFile时,上升的是Size和Committed列。

当访问这些map的数据时,上升的是Total Working Set和Sharable Working Set。

调用UnmapViewOfFile时,Size,Committee和Working set列都下降。

调用CloseHandle来关闭CreateFileMapping创建的handle时,不影响任何列, 但是减少了系统的Total Commit Charge。

 

共享状态下的Memory based CreateFileMapping

需要注意的是这个file mapping命名了,并且是在同一个进程中打开两次,以达到共享的目的。

受影响的是VMMap中的Sharable列。

调用第一个调用CreateFileMapping时,不影响任何列,增加的只是系统的Total Commit Charge。

调用MapViewOfFile时,上升的是Size和Committed列。

当访问这些map的数据时,上升的是Total Working Set和Sharable Working Set。

以上行为跟前面一个Scenario完全一样,下面要开始创建再次打开刚才创建的File mapping.

当用同样的名字再次调用CreateFileMapping打开前面创建的file mapping时,系统的Total Commit Charge不受影响,也不影响VMMap中的任何列。

调用MapViewOfFile时,上升的是Size和Committed列。也就是说,上升第二次了。

当访问这些map的数据时,上升的是Total Working Set和Sharable Working Set。也是上升第二次。

调用UnmapViewOfFile来ummap掉第二次打开的view,Size,,commmited和working set都下降一半。

调用UnmapViewOfFile来ummap掉第一次打开的view,Size,,commmited和working set都下降到初始状态。

调用CloseHandle来关闭第二次打开的Handle,Total Commit charge不受影响。

调用CloseHandle来关闭第一次打开的Handle,Total Commit charge下降。

 

File Based CreateFileMapping

受影响的是Mapped File行。

调用CreateFileMapping时,没有影响到VMMap中的任何列,并且跟Memory Based File mapping不一样的是,Total Commit Charge也不受 影响,因为他是以File 作为back up的

调用MapViewOfFile时,上升的是Size和Committed列。跟Memory Based File mapping一样的表现。

当访问这些map的数据时,上升的是Total Working Set和Sharable Working Set。跟Memory Based File mapping一样的表现。

调用UnmapViewOfFile时,Size,Committee和Working set列都下降。跟Memory Based File mapping一样的表现。

调用CloseHandle来关闭CreateFileMapping创建的handle时,不影响任何列, 也不影响Total Commit Charge。

总结:file based和memory based不同点在于:

  1. File based影响是Mapped file行,memory based影响的是Sharable行。
  2. File based 不影响total commit charge, memory based 影响。



<think>我们正在讨论vmmap命令和虚拟内存映射。用户询问的是vmmap命令的使用方法或操作系统中的虚拟内存映射。根据之前的引用[1],我们知道内存管理器提供了一系列系统服务,包括分配和释放虚拟内存、在进程间共享内存、将文件映射到内存等。vmmap命令正是用于查看虚拟内存映射的工具(特别是在macOS系统中)。我将分为两部分回答:1.虚拟内存映射的基本概念(操作系统层面)2. vmmap命令的具体使用方法(以macOS为例)注意:由于用户可能使用的是macOS(因为vmmap是macOS中的命令),但虚拟内存映射的概念是通用的。第一部分:虚拟内存映射在操作系统中,每个进程都有自己的虚拟地址空间。虚拟内存映射是指将虚拟地址与物理内存、文件或其他资源关联起来的过程。操作系统通过内存管理单元(MMU)实现地址转换。常见的内存映射类型包括:-私有匿名映射:用于进程的堆、栈等,不与文件关联,且写时复制(Copy-on-Write)。-共享匿名映射:用于进程间共享内存(如POSIX共享内存)。-私有文件映射:将文件映射到进程的地址空间,用于加载可执行文件和动态库,修改不会写回文件。-共享文件映射:多个进程共享同一个文件映射,修改会同步到文件。第二部分:vmmap命令vmmap是macOS(以及iOS)中用于分析进程虚拟内存布局的命令行工具。它可以显示进程的整个虚拟地址空间的布局,包括每个内存区域的属性(读/写/执行)、大小、所属的段(如__TEXT, __DATA,__LINKEDIT等)、映射的文件路径(如果有)等。基本用法:vmmap[options] <pid |partial-process-name |memory-graph>常用选项:-summary:按类型(如MALLOC,STACK,IMAGE等)汇总内存使用情况。-pages:按分页显示详细信息(默认是按区域显示)。-resident:显示驻留内存(实际在物理内存中的部分)的统计。-allRegions:显示所有区域(包括系统保留区域)。-interleaved:交错显示所有区域(不按类型分组)。示例:1.查看进程1234的内存映射:`vmmap1234`2.按类型汇总:`vmmap-summary1234`3.查看Xcode的内存映射(通过进程名):`vmmap Xcode`输出解析:vmmap的输出包含多个部分,每个部分代表一个虚拟内存区域(VMRegion)。每个区域的信息包括:-起始地址和结束地址-大小-保护标志(rwx/等)-映射类型(如MALLOC_TINY, STACK,__TEXT等)-详细路径(如果是文件映射)注意:在macOS中,vmmap需要权限。如果使用sudo,可以查看其他用户进程的内存映射。相关概念:-虚拟内存区域(VMRegion):连续的虚拟地址范围,具有相同的属性(保护、类型等)。-段(Segment):在Mach-O可执行文件中定义的段(如__TEXT, __DATA),被映射到虚拟地址空间。-内存图(MemoryGraph):在macOS中,可以通过`leaks`命令生成内存图,然后用vmmap分析。最后,我们可以生成一些相关问题,以帮助用户深入理解。</think>### vmmap命令与虚拟内存映射解析 #### 一、虚拟内存映射基础 在操作系统中,虚拟内存映射是将物理内存、文件或设备映射到进程虚拟地址空间的核心机制[^1]。关键特性包括: 1. **地址空间隔离**:每个进程拥有独立的$4GB$(32位)或$256TB$(64位)虚拟地址空间 2. **映射类型**: - 文件映射:将磁盘文件(如可执行文件)映射到内存 - 匿名映射:分配零初始化的物理内存页(如堆内存) - 共享映射:进程间共享数据(`mmap`的`MAP_SHARED`标志) 3. **分页机制**:通过页表实现虚拟地址到物理地址的转换,由MMU硬件加速 #### 二、vmmap命令详解(macOS/Linux) **vmmap**是分析进程内存布局的专业工具,基本语法: ```bash vmmap [options] <pid | process-name> ``` ##### 常用选项: | 选项 | 作用 | |------|------| | `-pages` | 显示分页级详细信息 | | `-resident` | 显示驻留内存统计 | | `-summary` | 按类型汇总内存使用 | | `-interleaved` | 按地址排序输出 | ##### 输出解析示例: ``` REGION TYPE SIZE VIRTUAL __TEXT 384K [0x104fa4000->0x104fec000] __DATA 24K [0x104fec000->0x104ff2000] MALLOC_TINY 32K [0x7f95e0000000] STACK GUARD 16K [0x7fff5d3f0000] Stack 8192K [0x7fff5d400000] ``` - **__TEXT/__DATA**:程序代码段/数据段 - **MALLOC_**:动态分配内存区域 - **Stack**:线程栈空间 - 方括号显示虚拟地址范围:$[\text{start\_addr} \rightarrow \text{end\_addr}]$ #### 三、关键应用场景 1. **内存泄漏检测** 通过对比多次`vmmap`输出的堆内存变化定位泄漏区域: ```bash vmmap -summary MyApp > mem_report1.txt # 执行操作后... vmmap -summary MyApp > mem_report2.txt diff mem_report*.txt ``` 2. **文件映射验证** 检查文件是否正确加载到内存: ```bash vmmap MyApp | grep "Map File" ``` 3. **内存优化分析** 使用`-resident`标识内存实际使用率: ``` REGION TYPE DIRTY SWAP RESIDENT MALLOC_LARGE 128K 0K 64K (50%利用率) ``` #### 四、底层原理 虚拟内存映射通过系统调用实现: - **创建映射**:`mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)` - **修改保护**:`mprotect(void *addr, size_t len, int prot)` - **同步数据**:`msync(void *addr, size_t len, int flags)` - **解除映射**:`munmap(void *addr, size_t len)` 内存管理器通过页错误(Page Fault)处理机制动态加载数据: $$ \text{缺页次数} = \sum_{i=1}^{n} \delta(\text{page}_i \notin \text{RAM}) $$ 其中$\delta$为指示函数,触发时从磁盘加载数据到物理内存[^1]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值