转载请附上来源:Russell的博客彩色天空
1. 一个简单的问题:
计算机中很多看似简单的问题,回答起来往往不那么简单。
一个应用程序在某一时刻,到底是用了多少内存?
TaskManager中有两列Mem Usage和VM Size,哪一个值是程序占用的内存?它们之间又有着什么样的关系?
只有把操作系统的内存管理策略机制了解后,才能较好的回答这个问题。
![](https://www.cnblogs.com/images/cnblogs_com/colorsky/taskMg.JPG)
2. 虚拟存储器
现代操作系统大都使用虚拟内存管理机制,对应用程序而言,只需知道32位的操系统提供了最大2GB的内存空间(另外2GB由系统进程使用)。操作系统负责虚拟存储器《=》物理内存的调度。概念上而言,虚拟存储器(VM)被组织为一个存放在磁盘上的N个连续的字节数组。每个字节都有个唯一的虚拟地址。
2.1. 虚拟存储器《=》物理内存
2.1.1. 理论
为了得到运行时的高效率,虚存中的数组被缓存在主存中(物理内存)。虚存和主存之间的传输单位叫做页(Page) 。目前的Win32操作系统下Page Size = 4KB字节大小。(可以由API GetSystemInfo()取得)
再任意时刻虚存中的页面被分为3个不相交的子集:
· 未分配的:VM系统还未分配的页
· 缓存的:当前缓存在物理存储器中的已分配页。
· 未缓存的:没有缓存在物理存储器中的已分配页。
![](https://www.cnblogs.com/images/cnblogs_com/colorsky/mem.JPG)
2.1.2. 实现
在Windows中,虚存中的页面被分为下面3个不相交的子集:
· 未分配的(Free)
· 保留的(Reserved): 保留指定范围的一段Free空间,等到以后需要的时候使用。
· 已分配的(Commit):VM Size的值,当程序访问时被调入主存。(原虚存空间保留)
可以通过API VirtualAlloc在虚存上分配上述类型的内存,注:程序如果访问Free或Reserved的地址,会产生access violation exception。
通过VirtualFree释放内存,注:VirtualFree会释放虚存及其被缓存在主存中的内存。
2.2. 如何找到要访问的内存
寻址由硬件MMU(CPU中)和操作系统共同完成。MMU接到虚拟地址后,查找虚存=〉主存的映射表,叫做页表(Page Table),进行地址翻译,转化成主存中的地址。页表由操作系统维护,每一个进程中都有一张页表。页表由连续的数组组成,每一个项目叫做PTE (Page Table Entry),都记录了一个虚存的页映射的主存中的页。
3. Working Set
尽管在整个运行过程中,程序引用的不同页面可能超出物理存储器总的大小,但是局部性原则保证在任意时刻,程序访问趋向于在一个较小的页面集合上工作,这个集合就是Working Set或常驻集合。当这个Working Set超出了主存的实际大小,那么程序将产生一种不幸的现象:颠簸 (thrashing) ,页面将不断地换进换出。
Working Set的大小就是Mem Usage的值,但是注意Working Set除了包含虚存中缓存的页外,还包括引用的Share进程的代码页(数据页在进程的私有空间中)。
注:进程访问共享库时(如NTDLL.DLL),代码页仍在NTDLL的进程中,其他访问者只保留对它的映射,但是数据段是每个进程一份。
显然Share进程的代码页在每个调用者的Mem Usage中被重复计算,这也是有时候Mem Usage的值大于VM Size原因。
4. 答案
现在来回答我们开始题的问题,程序分配的内存包括:申请的保留内存页(Reserved),虚存中已分配的内存页(Commit)和被缓存在主存中的物理页。
根据上面的分析:一个程序占用的内存=Reserved Memory(在虚存上) + Committed Memory (VM Size) + (Mem Usage – Shared Code Page)。
5. 示例:
TestMEM.c
刚开始申请200M的Reserved 内存空间,这时候VMSize和MEM Usage没有变化。
接着将其中的100M转化成Commit,可以看到VMSize猛增到100M,MEM Usage没有变化。
接着循环使用指针变量P指向在Commit的页面中的起始地址位置,并付值’x’,可以看到MEM Usage逐渐增长,VMSize不变。
还可以观察Page Faults的值,了解页失效。
/Files/ColorSky/testmem.txt
另附知秋一叶的精彩论述:
http://blog.joycode.com/qqchen/archive/2004/03/17/16434.aspx
1. 一个简单的问题:
计算机中很多看似简单的问题,回答起来往往不那么简单。
一个应用程序在某一时刻,到底是用了多少内存?
TaskManager中有两列Mem Usage和VM Size,哪一个值是程序占用的内存?它们之间又有着什么样的关系?
只有把操作系统的内存管理策略机制了解后,才能较好的回答这个问题。
2. 虚拟存储器
现代操作系统大都使用虚拟内存管理机制,对应用程序而言,只需知道32位的操系统提供了最大2GB的内存空间(另外2GB由系统进程使用)。操作系统负责虚拟存储器《=》物理内存的调度。概念上而言,虚拟存储器(VM)被组织为一个存放在磁盘上的N个连续的字节数组。每个字节都有个唯一的虚拟地址。
2.1. 虚拟存储器《=》物理内存
2.1.1. 理论
为了得到运行时的高效率,虚存中的数组被缓存在主存中(物理内存)。虚存和主存之间的传输单位叫做页(Page) 。目前的Win32操作系统下Page Size = 4KB字节大小。(可以由API GetSystemInfo()取得)
再任意时刻虚存中的页面被分为3个不相交的子集:
· 未分配的:VM系统还未分配的页
· 缓存的:当前缓存在物理存储器中的已分配页。
· 未缓存的:没有缓存在物理存储器中的已分配页。
2.1.2. 实现
在Windows中,虚存中的页面被分为下面3个不相交的子集:
· 未分配的(Free)
· 保留的(Reserved): 保留指定范围的一段Free空间,等到以后需要的时候使用。
· 已分配的(Commit):VM Size的值,当程序访问时被调入主存。(原虚存空间保留)
可以通过API VirtualAlloc在虚存上分配上述类型的内存,注:程序如果访问Free或Reserved的地址,会产生access violation exception。
通过VirtualFree释放内存,注:VirtualFree会释放虚存及其被缓存在主存中的内存。
2.2. 如何找到要访问的内存
寻址由硬件MMU(CPU中)和操作系统共同完成。MMU接到虚拟地址后,查找虚存=〉主存的映射表,叫做页表(Page Table),进行地址翻译,转化成主存中的地址。页表由操作系统维护,每一个进程中都有一张页表。页表由连续的数组组成,每一个项目叫做PTE (Page Table Entry),都记录了一个虚存的页映射的主存中的页。
3. Working Set
尽管在整个运行过程中,程序引用的不同页面可能超出物理存储器总的大小,但是局部性原则保证在任意时刻,程序访问趋向于在一个较小的页面集合上工作,这个集合就是Working Set或常驻集合。当这个Working Set超出了主存的实际大小,那么程序将产生一种不幸的现象:颠簸 (thrashing) ,页面将不断地换进换出。
Working Set的大小就是Mem Usage的值,但是注意Working Set除了包含虚存中缓存的页外,还包括引用的Share进程的代码页(数据页在进程的私有空间中)。
注:进程访问共享库时(如NTDLL.DLL),代码页仍在NTDLL的进程中,其他访问者只保留对它的映射,但是数据段是每个进程一份。
显然Share进程的代码页在每个调用者的Mem Usage中被重复计算,这也是有时候Mem Usage的值大于VM Size原因。
4. 答案
现在来回答我们开始题的问题,程序分配的内存包括:申请的保留内存页(Reserved),虚存中已分配的内存页(Commit)和被缓存在主存中的物理页。
根据上面的分析:一个程序占用的内存=Reserved Memory(在虚存上) + Committed Memory (VM Size) + (Mem Usage – Shared Code Page)。
5. 示例:
TestMEM.c
刚开始申请200M的Reserved 内存空间,这时候VMSize和MEM Usage没有变化。
接着将其中的100M转化成Commit,可以看到VMSize猛增到100M,MEM Usage没有变化。
接着循环使用指针变量P指向在Commit的页面中的起始地址位置,并付值’x’,可以看到MEM Usage逐渐增长,VMSize不变。
还可以观察Page Faults的值,了解页失效。
/Files/ColorSky/testmem.txt
另附知秋一叶的精彩论述:
http://blog.joycode.com/qqchen/archive/2004/03/17/16434.aspx