2011-06-24 111 views
9

我想了解堆碎片如何工作。以下輸出告訴我什麼?託管堆碎片

這堆是否過分分散?

我有243010個「自由對象」,總數爲53304764個字節。那些曾經包含對象但現在已經收集到garabage的堆中的那些「自由對象」空間?

如何強制碎片堆清理?

!dumpheap -type Free -stat 
total 243233 objects 
Statistics: 
     MT Count TotalSize Class Name 
0017d8b0 243010  53304764  Free 

回答

6

這取決於你的堆是如何組織的。你應該看看Gen 0,1,2中有多少內存被分配,以及你在那裏有多少空閒內存,與所使用的內存總數相比。 如果你有500 MB託管堆使用,但50 MB是免費的,那麼你做得很好。如果您執行內存密集型操作(如創建多個WPF控件並釋放它們),則短時間內需要更多內存,但.NET在分配內存後不會將內存重新提供給操作系統。 GC試圖識別分配模式,並且趨向於保持內存佔用高,儘管當前的堆大小太大,直到機器在物理內存上運行不足。

我發現在.NET 3.5中使用psscor2要容易得多,它有一些很酷的命令,如ListNearObj,您可以在其中找到哪些對象位於內存空間(固定對象?)周圍。使用psscor2的命令,您可以更好地瞭解您的堆中究竟發生了什麼。大多數命令也可以在.NET 4中的SOS.dll中使用。

要回答你的原始問題:是的自由對象是託管堆上的空白,它可以簡單地作爲GC區段中最後分配的對象之後的空閒內存塊。或者如果你這樣做了!DumpHeap和GC段的起始地址,你可以看到分配在該託管堆段中的對象以及作爲GC收集對象的自由對象。

該存儲空洞通常在Gen2中發生。自由對象之前和之後的對象地址確實告訴你什麼潛在的固定對象在你的洞周圍。從這裏你應該能夠確定你的分配歷史,並在需要時進行優化。 你可以找到GC堆上的地址與

0:021> !EEHeap -gc 
Number of GC Heaps: 1 
generation 0 starts at 0x101da9cc 
generation 1 starts at 0x10061000 
generation 2 starts at 0x02aa1000 
ephemeral segment allocation context: none 
segment  begin allocated size 
02aa0000 02aa1000** 03836a30 0xd95a30(14244400) 
10060000 10061000** 103b8ff4 0x357ff4(3506164) 
Large object heap starts at 0x03aa1000 
segment  begin allocated size 
03aa0000 03aa1000 03b096f8 0x686f8(427768) 
Total Size:    Size: 0x115611c (18178332) bytes. 
------------------------------ 
GC Heap Size:   Size: 0x115611c (18178332) bytes. 

還有你看,你在02aa1000有堆和10061000. 有了!DumpHeap 02aa1000 03836a30你可以轉儲GC堆段。

!DumpHeap 02aa1000 03836a30 
    Address MT    Size 
    ... 
    037b7b88 5b408350  56  
    037b7bc0 60876d60  32  
    037b7be0 5b40838c  20  
    037b7bf4 5b408350  56  
    037b7c2c 5b408728  20  
    037b7c40 5fe4506c  16  
    037b7c50 60876d60  32  
    037b7c70 5b408728  20  
    037b7c84 5fe4506c  16  
    037b7c94 00135de8 519112 Free 
    0383685c 5b408728  20  
    03836870 5fe4506c  16  
    03836880 608c55b4  96 
    .... 

在那裏你可以找到你的空閒內存塊,這是一個已經被GCed過的對象。您可以轉儲周圍的對象(輸出是按地址明智排序的),以確定它們是固定還是具有其他不尋常的屬性。

+0

可以堆碎片發生(並最終導致OutOfMemoryException)**沒有**固定對象?我瞭解GC是清理碎片堆的人。如果沒有固定對象,GC是否仍然無法及時清理堆以便發出新的內存請求?固定對象除外,可能會導致一個碎片堆,無法在新分配需要完成時清理(及時)? – bitbonk

+0

如果分配率非常高,則可能會導致內存不足。如果你在緊張的環路中分配給GC提供清理的機會,但clr確實有一個內置的Sleep(50)來限制你的分配請求,但這可能是不夠的。 –

0

您有50MB的RAM作爲可用空間。不是很好。

讓.NET從進程中分配16MB的塊,我們確實有一個碎片問題。 在.NET中出現碎片的原因很多。

看一看herehere。 在你的情況下,它可能是一個釘住。由於53304764/243010使每個對象219.35字節 - 遠低於LOH對象。

+0

好吧,我有50MB的可用空間,但那* Count *告訴我什麼? 我知道我經常創建大量的小對象(即每隔10秒創建一個約20000個WPF控件的網格,但舊的變爲未引用,這裏沒有內存泄漏)。這可以解釋它還是應該固定物體更可能。 – bitbonk