32位操做系統的尋址空間是4G,其中有2G被操做系統佔用,也就是說留給用戶進程的內存只有2G(其中還要扣除程序加載時映像佔用的部分空間,通常只有1.6G~1.8G左右可使用)。緩存
若是進程運行中須要申請內存,而操做系統沒法爲其分配內存空間,則會產生內存不足的異常,在.net中爲System.OutOfMemoryException(The exception that is thrown when there is not enough memory tocontinue the execution of a program.)。dom
雖然最終的表現都爲OutOfMemoryException,但其產生的緣由多是不同的,動手解決此問題以前須要先對進程當前內存的使用狀態進行分析,找出正確的緣由,才能對症下藥。下面分享一下調試此類問題的一些心得。性能
1、使用Perfmon.exe測試
1) 命令行輸入perfmon.exe。打開「性能」。操作系統
2) 在「性能日誌與警報-計數器日誌」上右鍵,選擇「新建日誌設置」。.net
3) 輸入日誌名稱,如「OOM」。命令行
4) 在「常規-計數器」中刪除全部默認的計數器(若是有)。調試
5) 點擊「添加計數器」,性能對象選擇「.NET CLR Memory」,計數器選擇並添加「Bytes in all heaps」、「Large Object Heap Size」。一樣「性能對象」選擇「Process」,計數器選擇並添加「Virtual bytes」、」Private bytes」。注意點擊「添加」前須要在「從列表選擇範例」選擇框選擇須要監控的進程。
日誌
另外,若是當前系統登錄的用例對目標進程沒有調試權限,須要在「運行方式」框裏填入domain\username,並輸入密碼。對象
6) 數據採樣間隔能夠設置小一點,如1秒鐘。
7) 點擊「肯定「,新的計數器日誌就新建成功了。右邊的框框中能夠看到新的計數器,綠色表示正在運行中。」「日誌文件名「列顯示了本次監控結果將寫入的日誌文件名(同一個計數器運行屢次,寫入的日誌文件名是不一樣的)。
8) 讓程序與計數器運行一段時間,而後中止計數器(爲何要中止計數器?個人機器上測試的時候,須要先中止計數器後,纔會把監控的結果寫到日誌文件中,若是不先中止,在下面的監視器中將看不到計數器運行這段時間的監控結果。)。
9) 點擊「系統監視器「。點擊」「查看日誌數據」(圖標爲)按鈕,在「來源」選項卡里添加日誌文件爲剛剛咱們新建的計數器產生的日誌文件。下方可選擇時間範圍,這裏選所有便可。而後在「數據」選項卡里添加須要查看的計數器(此選擇卡還能夠定義不一樣的計數器顯示的樣式及顯示比例)。
10) 從圖上能夠看到在計數器運行的時間段中,被監控進程的內存使用狀況。在添加計數器的窗口中有對相應計數器的簡單說明,下面是幾個經常使用的計數器:
· Bytes in all Heaps:.net託管堆(GC)使用的總內存。包括0代、1代、2代及大對象堆。
· Large Object Heap size:大對象堆使用的內存。.net在分配內存時大於85K的對象會被放到這個堆中,不一樣於0、一、2代,大對象堆中的內存不是連續的,在垃圾回收時也不會移動大對象的地址(我係統顯示爲大於20K對象爲大對象,實際上2.0應該爲大於85K)。
· Private bytes:該計數器記錄了當前經過VirtualAlloc API Commit的Memory數量。不管是直接調用API申請的內存,被Heap Manager申請的內存,或者是CLR 的managed heap,都算在裏面。跟Handle Count同樣,若是在整個程序週期內整體趨勢是連續向上,說明有MemoryLeak(摘自百度)。
· Virtual bytes:該計數器記錄了當前進程申請成功的用戶態總內存地址,包括DLL/EXE佔用的地址和經過VirtualAlloc API Reserve的Memory Space數量,因此該計數器應該總大於Private Bytes。通常來講,Virtual Bytes跟Private Bytes的變化大體一致。因爲內存分片的存在, Virtual Bytes跟Private Byes通常保持一個相對穩定的比例關係。當Virtual Bytes跟Private Bytes的比例關係大於2的時候,程序每每有比較嚴重的內存地址分片(摘自百度,但對.net程序來講通常差異在200M如下還算是正常的)。
11) 有了上面幾個計數器的結果以後,通常能夠經過如下規則大體定位問題的所在:
· Virtual bytes增加但Private bytes沒有顯著增加。爲Virtual bytes泄露。
· Private bytes增加但bytes in all heaps沒有顯著增加。爲非託管資源泄露,檢查有沒有COM組件或其它非託管調用沒有正確釋放內存。
· Bytes in all heaps顯著增加。爲.net託管內存泄露。因爲.net內存是GC管理的,自動回收,這裏有多是緩存了過多的數據,或程序中引用混亂致使原本須要被回收的數據還被其它對象所引用從而GC無法回收這部分數據。
· Bytes in all heaps有增加但使用很少,系統剩餘可用內存也比較多(須要再添加相應的計數器)。這種狀況比較少見,但我遇到過一次是因爲非託管在存在大量碎片,致使.net在申請大對象時失敗。原文:https://blog.csdn.net/lazyleland/article/details/6704661