10

我试图了解堆碎片化的工作原理。以下输出告诉我什么?

这个堆是否过于碎片化?

我有 243010 个“免费对象”,总共 53304764 个字节。堆中那些曾经包含对象但现在被垃圾收集的“自由对象”空间是否存在?

如何强制碎片堆清理?

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

2 回答 2

7

这取决于您的堆是如何组织的。您应该查看 Gen 0、1、2 中分配了多少内存,以及与总已用内存相比,您有多少可用内存。如果您使用了 500 MB 托管堆但 50 MB 是空闲的,那么您做得很好。如果您执行内存密集型操作,例如创建许多 WPF 控件并释放它们,那么您在短时间内需要更多内存,但 .NET 不会在分配内存后将内存返还给操作系统。GC 尝试识别分配模式并倾向于保持较高的内存占用,尽管您当前的堆大小太大,直到您的机器物理内存不足。

我发现在 .NET 3.5 中使用psscor2要容易得多,它有一些很酷的命令,例如ListNearObj,您可以在其中找出内存孔周围的对象(固定对象?)。使用来自 psscor2 的命令,您有更好的机会找出堆中真正发生的事情。大多数命令在 .NET 4 的 SOS.dll 中也可用。

回答您最初的问题:是的,空闲对象是托管堆上的间隙,它可以简单地是您在 GC 段上最后分配的对象之后的空闲内存块。或者,如果您使用 GC 段的起始地址执行 !DumpHeap,您会看到在该托管堆段中分配的对象以及作为 GC 收集对象的空闲对象。

这种内存漏洞通常发生在 Gen2 中。自由对象之前和之后的对象地址确实会告诉您孔周围有哪些可能被固定的对象。从这里您应该能够确定您的分配历史记录并在需要时对其进行优化。你可以找到 GC Heaps 的地址

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 Heap 段。

!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 的对象。您可以转储周围的对象(输出按地址排序)以查明它们是否被固定或具有其他不寻常的属性。

于 2011-07-01T21:43:19.050 回答
0

您有 50MB 的 RAM 作为可用空间。不是很好。

让 .NET 从进程中分配 16MB 的块,我们确实遇到了碎片问题。.NET 中出现碎片的原因有很多。

看看这里这里。在你的情况下,它可能是一个固定。由于 53304764 / 243010 每个对象占用 219.35 个字节 - 远低于 LOH 对象。

于 2011-06-30T14:54:13.327 回答