標籤:
Windows工作管理員預設情況下,“記憶體(私人工作集)”列處於選中狀態。
記憶體 - 工作集:是私人工作集中的記憶體數量與進程正在使用且可以由其他進程共用的記憶體數量的總和。
記憶體 - 峰值工作集:是進程所使用的工作集記憶體的最大數量。
記憶體 - 工作集增量:是進程所使用的工作集記憶體中的更改量。
記憶體 - 專用工作集:- 是工作集的一個子集,它是描述每個進程所使用的記憶體數量的技術術語。專用工作集專門描述了某個進程正在使用的且無法與其他進程共用的記憶體數量。
記憶體 - 提交大小:是為某進程使用而保留的虛擬記憶體的數量。
記憶體 - 頁面緩衝池:是可以寫入其他儲存媒體(例如硬碟)的某個進程的認可虛擬記憶體數量。
記憶體 - 非頁面緩衝池:是無法寫入其他儲存媒體的某個進程的認可虛擬記憶體數量。
一. SetProcessWorkingSetSize 的工作原理
看看這個API SetProcessWorkingSetSize
這是從MSDN摘下的原話
Using the SetProcessWorkingSetSize function to set an application‘s minimum and maximum working set sizes does not guarantee that the requested memory will be reserved, or that it will remain resident at all times. When the application is idle, or a low-memory situation causes a demand for memory, the operating system can reduce the application‘s working set. An application can use the VirtualLock function to lock ranges of the application‘s virtual address space in memory; however, that can potentially degrade the performance of the system.
使用這個函數來設定應用程式最小和最大的Runspace,只會保留需要的記憶體。當應用程式被閑置或系統記憶體太低時,作業系統會自動調用這個機制來設定應用程式的記憶體。應用程式也可以使用 VirtualLock 來鎖住一定範圍的記憶體不被系統釋放。
When you increase the working set size of an application, you are taking away physical memory from the rest of the system. This can degrade the performance of other applications and the system as a whole. It can also lead to failures of operations that require physical memory to be present; for example, creating processes, threads, and kernel pool. Thus, you must use the SetProcessWorkingSetSize function carefully. You must always consider the performance of the whole system when you are designing an application.
當你加大Runspace給應用程式,你能夠得到的實體記憶體取決於系統,這會造成其他應用程式降低效能或系統總體降低效能,這也可能導致請求實體記憶體的操作失敗,例如:建立 進程,線程,核心池,就必須小心的使用該函數。
========================
事實上,使用該函數並不能提高什麼效能,也不會真的節省記憶體。
因為他只是暫時的將應用程式佔用的記憶體移至虛擬記憶體,一旦,應用程式被啟用或者有操作請求時,這些記憶體又會被重新佔用。如果你強制使用該方法來 設定程式佔用的記憶體,那麼可能在一定程度上反而會降低系統效能,因為系統需要頻繁的進行記憶體和硬碟間的頁面交換。
BOOL SetProcessWorkingSetSize(
HANDLE hProcess,
SIZE_T dwMinimumWorkingSetSize,
SIZE_T dwMaximumWorkingSetSize
);
將 2個 SIZE_T 參數設定為 -1 ,即可以使進程使用的記憶體交換到虛擬記憶體,只保留一小部分代碼
1 。當我們的應用程式剛剛載入完成時,可以使用該操作一次,來將載入過程不需要的代碼放到虛擬記憶體,這樣,程式載入完畢後,保持較大的可用記憶體。
2.程式運行到一定時間後或程式將要被閑置時,可以使用該命令來交換佔用的記憶體到虛擬記憶體。
二. 區分實體記憶體、虛擬記憶體、Working Set(Memory)、Memory
以下來自:http://blog.joycode.com/qqchen/archive/2004/03/17/16434.aspx
這個問題在CSDN上碰到好幾次,我每次都只給出了簡單的答案:不要參考Task Manager的Mem Usage資料,那個資料的大小對程式效能沒有直接影響。
下面是我分析這問題的一些思路,希望對對這個問題感興趣的朋友有所協助
Q: Is .NET Alone?
A: Nope! 前面Saucer說過了,這不是.NET的問題,所有Windows程式都有類似的行為。例如下面的C程式:
void main { while(1); } //死迴圈,便於我們察看Task Manager
初次運行在我的機器上Mem Usage是632K,把Console最小化以後再恢複,Mem Usage變成了36K。顯然,這不是一個.NET專屬的問題,而是Windows Memory Management的問題。那麼和.NET的GC機制也不會有太大的關係——雖然問題的表現形式很容易讓人聯想到GC。
Q: How much memory does my program use?
A: 回答這個問題並不容易。先來看看作業系統虛擬記憶體管理的一些基本概念:每個Windows進程都擁有4G的地址空間,但是你的機器顯然沒有4G的實體記憶體。在多任務環境下,所有進程使用的記憶體總和可以超過電腦的實體記憶體。在特定的情況下,進程的一部分可能會從實體記憶體中刪除而被暫存在硬碟的檔案裡(pagefile),當進程試圖訪問這些被交換到pagefile裡的記憶體的時候,系統會產生一個缺頁中斷(page fault),這時候Windows記憶體管理器會負責把對應的記憶體頁重新從硬碟調入實體記憶體。
在某個時間內,一個進程可以直接存取到的實體記憶體(不發生缺頁中斷)叫做這個進程的Working Set;而一個進程從4G的地址空間當中實際分配(commit)了的、可訪問的記憶體稱為Committed Virtual Memory。Committed VM可能存在於Page File當中,WorkingSet則一定位於實體記憶體。
所以要回答上面的問題先要反問一句:What‘re you talking about? Physical Memory or Committed Memory?
Q: What is this "Mem Usage" data?
A: From Task Manager Help: In Task Manager, the current Working Set of a process, in kilobytes.
Mem Usage這個名字多少有些誤導。它只表示這個進程當前佔用的實體記憶體,也就是WorkingSet。WorkingSet不表示進程當前“佔用”的所有虛擬記憶體,該進程可能還有一部分資料被交換到pagefile當中。這些資料只有在被訪問的時候才會被載入到實體記憶體。
Task Manager有另一列資料:VM Size,表示了一個進程分配的虛存(Committed Visual Memory)——實際的定義要比這個複雜一些,但這個定義對我們目前分析的問題已經足夠了。以前面的C程式為例,在最小化前後的VM Size都是176K,並沒有變化。
所以,結論很簡單:當一個Windows程式被最小化的時候,Windows記憶體管理器把該進程的WorkingSet減到最小(根據先進先出FIFO或者最近最少使用LRU),把大部分資料交換到pagefile裡。這很容易理解:我們通常總是希望為前台的應用程式留出更多實體記憶體,從而具有更好的效能。當該程式從最小化恢複的時候,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太小,程式運行過程中會產生很多缺頁中斷,這會嚴重影響程式的效能。另一方面,WorkingSet太大會浪費“寶貴的”實體記憶體,降低整個系統的效能。 通常情況下(除非是對效能非常敏感的應用程式,並且你對Windows的記憶體管理了如指掌),建議不要在程式中自己調整WorkingSet的大小,而把這個任務交給Windows記憶體管理器。調整的方法Saucer有提到: SetProcessWorkingSetSize();
Q: Final Question, Does my program really occupy that much physical memory?
A: 這個問題看上去土了點——那個數字明明白白的寫在Task Manager裡面。
sam1111用vadump檢查的結果顯示進程WorkingSet減小的主要原因是很多DLL在從最小化恢複的時候沒有被載入到實體記憶體。我們知道DLL的一個特點是代碼共用,以NTDLL.DLL為例,整個Windows系統的幾乎所有應用程式(具體地說,Win32子系統的所有程式)都需要引用NTDLL.DLL,如果每人一份,光這個檔案就的佔用幾十兆記憶體。Windows地解決辦法是只在實體記憶體中儲存一份NTDLL.DLL的COPY,所有引用這個DLL的程式都把這一份COPY映射到自己的記憶體空間裡面,共用NTDLL.DLL的程式碼片段(每個進程的資料區段仍然是獨立的)。所以雖然NTDLL.DLL的大小被計算在你的程式的WorkingSet裡面,但是從你的程式中去掉對這個DLL的引用並不會真的釋放多少實體記憶體——你不用,別人還在用呢!
所以,你的程式“獨佔”的實體記憶體遠沒有Mem Usage所表示的那麼多,需要從Mem Usage裡面扣除很多Shared Code Page (vadump裡面可以看到)。
結論?不要參考Task Manager的Mem Usage資料,那個資料的大小對程式效能沒有直接影響。用Perfomence Monitor裡面與.NET相關的Counter要容易、準確的多
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Windows工作集記憶體