惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
I
InfoQ
C
Check Point Blog
IT之家
IT之家
MyScale Blog
MyScale Blog
Apple Machine Learning Research
Apple Machine Learning Research
Vercel News
Vercel News
Last Week in AI
Last Week in AI
GbyAI
GbyAI
P
Proofpoint News Feed
量子位
Stack Overflow Blog
Stack Overflow Blog
Microsoft Azure Blog
Microsoft Azure Blog
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
B
Blog
T
The Blog of Author Tim Ferriss
H
Help Net Security
云风的 BLOG
云风的 BLOG

博客园 - ColorSky

小议winForm的热键 一定要找到你--IE隐藏文件 One sentence humor Self-service How do you add reference dll from GAC? 其实它不是我想象 关于目标 英语文化陷井 Everyday English - Glove Troubleshooting for Asp.net CS0016 error [ZZ]C#四种排序算法 唐僧的家书 minute_DesignPatternExplained(4) 管理的问题-聪明和笨的程序员 揭秘devenv 如何以两种启动模式启动 程序员,为你的程序而骄傲吧 算法的力量 minute_DesignPatternExplained(2) 转载同事写的:2006TechED感想
一个应用程序在某一时刻,到底是用了多少内存?
ColorSky · 2006-11-16 · via 博客园 - ColorSky

转载请附上来源:Russell的博客彩色天空

 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