最近经常碰到很多同事讨论各种内存相关的名词,我想在这里总结一下,希望有相同疑问的人能有所帮助。
讨论涉及到的名词如下:
- free memory
- reserved memory
- committed memory
- virtual memory
- private memory
- shared memory
- working set
1. free memory, reserved memory, committed memory
这三个名词是用来形容用户空间中虚拟内存的状态的。既然说是形容状态就要有状态对应的属性,他们的关系可以用下面的表格说明:
内存状态 | VAD | 物理介质 |
Free | 没有VAD对应。 | 没有物理介质的支撑。 |
Reserved | 每块这种内存会对应一个VAD。 | 没有物理介质的支撑。 |
Committed | 每块这种内存会对应一个VAD。 | 每块内存可被paging file(即物理内存),或者普通file mapping支撑。 |
* VAD (virtual address descriptor)是用来描述内存中虚拟地址的数据结构。可以用windbg扩展命令!vad查看其具体属性。
2. private memory,shared memory
这两个概念是按照内存的共享状态区分的,他们都只用于描述Committed内存的状态。
如果一块虚拟内存是通过VirtualAlloc()提交的,那么这块内存只能被当前进程使用,所以叫它private memory。
如果一块虚拟内存是通过CreateFileMapping()提交的(无论使用页面文件支撑还是使用普通文件映射支撑),这些内存就可以被别的进程映射,从而与别的进程共享。不论实际中这些内存是不是被真的共享,系统都把这种内存算成shared memory。
3. working set
前面的名词都是用来讨论虚拟内存的概念,working set是表示进程实际使用的物理内存的数量。有一种认识是working set应该总是小于或等于private memory size,这是错误的。下面的实验可以说明:
a) 用VirtualAlloc()分配1M内存
b) 用CreateFileMapping()映射一个500M的普通文件
c) 顺序访问文件
这时候就会看到working set迅速增长到500M左右,但是private byte基本不变(几M左右)。原因就是系统读文件是用cache manager缓存文件到物理内存的,系统会把这些物理内存算到调用进程的working set中。
这里想到的另一个问题是,如果多个进程都引用这个文件,每个进程的working set都会计算这块cache占用的物理内存大小,这就是为什么把所以进程的working set加起来通常会大于系统的物理内存大小。