程序最小化后释放了很多的内存的原因
程序最小化后釋放了很多的內(nèi)存的原因
http://soartomato.iteye.com/blog/726135- 博客分類:?
- expr
偶然發(fā)現(xiàn)程序最小化后在task manager中的mem usage的數(shù)值會有大幅度的下降,本以為自己的程序有問題,其實這個是windows內(nèi)存管理策略的原因(FIFO or LRU),轉(zhuǎn)載一個非常不錯的文章,對這個問題有著詳細的解釋。原文網(wǎng)址如下:http://astarring.iteye.com/blog/525692
?
Task Manager的Mem Usage數(shù)據(jù) 與 VM Size
下面是我分析這問題的一些思路,希望對對這個問題感興趣的朋友有所幫助:?
Q: Is .NET Alone??
A: Nope! 前面Saucer說過了,這不是.NET的問題,所有Windows程序都有類似的行為。例如下面的C程序:?
void main { while(1); } //死循環(huán),便于我們察看Task Manager?
初次運行在我的機器上Mem Usage是632K,把Console最小化以后再恢復(fù),Mem Usage變成了36K。顯然,這不是一個.NET獨有的問題,而是Windows Memory Management的問題。那么和.NET的GC機制也不會有太大的關(guān)系——雖然問題的表現(xiàn)形式很容易讓人聯(lián)想到GC。?
Q: How much memory does my program use??
http://www.mscto.com?
A: 回答這個問題并不容易。先來看看操作系統(tǒng)虛擬內(nèi)存管理的一些基本概念:每個Windows進程都擁有4G的地址空間,但是你的機器顯然沒有4G的物理內(nèi) 存。在多任務(wù)環(huán)境下,所有進程使用的內(nèi)存總和可以超過計算機的物理內(nèi)存。在特定的情況下,進程的一部分可能會從物理內(nèi)存中刪除而被暫存在硬盤的文件里 (pagefile),當(dāng)進程試圖訪問這些被交換到pagefile里的內(nèi)存的時候,系統(tǒng)會產(chǎn)生一個缺頁中斷(page fault),這時候Windows內(nèi)存管理器會負責(zé)把對應(yīng)的內(nèi)存頁重新從硬盤調(diào)入物理內(nèi)存。?
在某個時間內(nèi),一個進程可以直接訪問到的物理內(nèi)存(不發(fā)生缺頁中斷)叫做這個進程的 Working Set ;而一個進程從4G的地址空間當(dāng)中實際分配(commit)了的、可訪問的內(nèi)存稱為 Committed Virtual Memory 。Committed VM可能存在于Page File當(dāng)中,WorkingSet則一定位于物理內(nèi)存。?
所以要回答上面的問題先要反問一句:What're you talking about? Physical Memory or Committed Memory??
Q: What is this "Mem Usage" data? 軟件開發(fā)網(wǎng)?
A: From Task Manager Help: In Task Manager, the current Working Set of a process, in kilobytes. 軟件開發(fā)網(wǎng)
Mem Usage這個名字多少有些誤導(dǎo)。它只表示這個進程當(dāng)前占用的物理內(nèi)存,也就是WorkingSet。WorkingSet不表示進程當(dāng)前“占用”的所有 虛擬內(nèi)存,該進程可能還有一部分數(shù)據(jù)被交換到pagefile當(dāng)中。這些數(shù)據(jù)只有在被訪問的時候才會被加載到物理內(nèi)存。?
Task Manager有另一列數(shù)據(jù):VM Size,表示了一個進程分配的虛存(Committed Visual Memory)——實際的定義要比這個復(fù)雜一些,但這個定義對我們目前分析的問題已經(jīng)足夠了。以前面的C程序為例,在最小化前后的VM Size都是176K,并沒有變化。?
所以,結(jié)論很簡單: 當(dāng)一個Windows程序被最小化的時候,Windows內(nèi)存管理器把該進程的WorkingSet減到最小(根據(jù)先進先出FIFO或者最近最少使用 LRU),把大部分數(shù)據(jù)交換到pagefile里。 這很容易理解:我們通常總是希望為前臺的應(yīng)用程序留出更多物理內(nèi)存,從而具有更好的性能。 當(dāng)該程序從最小化恢復(fù)的時候,Windows也不會完全加載程序的所有虛存,只是加載了必要的部分。 這也很容易理解:程序啟動階段的代碼通常在啟動之后很少訪問(對.NET程序尤其如此,向fusion這樣的模塊在程序正常加載之后如果沒有用到 Reflection通常用不到)。?
Q: So, Do we want a smaller workingset, or a larger one??
A: It depends. Conventional Wisdom tells us: The smaller, the better. 但是在虛存的問題上卻沒這么簡單。如果WorkingSet太小,程序運行過程中會產(chǎn)生很多缺頁中斷,這會嚴重影響程序的性能。另一方 面,WorkingSet太大會浪費“寶貴的”物理內(nèi)存,降低整個系統(tǒng)的性能。 通常情況下(除非是對性能非常敏感的應(yīng)用程序,并且你對Windows的內(nèi)存管理了如指掌),建議不要在程序中自己調(diào)整WorkingSet的大小,而把 這個任務(wù)交給Windows內(nèi)存管理器。調(diào)整的方法Saucer有提到: SetProcessWorkingSetSize ();?
Q: Final Question, Does my program really occupy that much physical memory? http://www.mscto.com?
A: 這個問題看上去土了點——那個數(shù)字明明白白的寫在Task Manager里面。?
sam1111 用vadump檢查的結(jié)果顯示進程WorkingSet減小的主要原因是很多DLL在從最小化恢復(fù)的時候沒有被加載到物理內(nèi)存。我們知道DLL的一個特點 是代碼共享,以NTDLL.DLL為例,整個Windows系統(tǒng)的幾乎所有應(yīng)用程序(具體地說,Win32子系統(tǒng)的所有程序)都需要引用 NTDLL.DLL,如果每人一份,光這個文件就的占用幾十兆內(nèi)存。Windows地解決辦法是只在物理內(nèi)存中保存一份NTDLL.DLL的COPY,所 有引用這個DLL的程序都把這一份COPY映射到自己的內(nèi)存空間里面,共享NTDLL.DLL的代碼段(每個進程的數(shù)據(jù)段仍然是獨立的)。所以雖然 NTDLL.DLL的大小被計算在你的程序的WorkingSet里面,但是從你的程序中去掉對這個DLL的引用并不會真的釋放多少物理內(nèi)存——你不用, 別人還在用呢!?
所以,你的程序“獨占”的物理內(nèi)存遠沒有Mem Usage所表示的那么多,需要從Mem Usage里面扣除很多Shared Code Page (vadump里面可以看到)。 http://www.mscto.com?
結(jié)論?不要參考Task Manager的Mem Usage數(shù)據(jù),那個數(shù)據(jù)的大小對程序性能沒有直接影響。 用Perfomence Monitor里面與.NET相關(guān)的Counter要容易、準確的多。
總結(jié)
以上是生活随笔為你收集整理的程序最小化后释放了很多的内存的原因的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vc6下c++编译器通不过,c编译器通过
- 下一篇: VB.NET程序如何巧妙释放内存