我在使用dotmemory分析一个Windows Forms应用程序的内存使用情况时,注意到对于我的应用程序,有0-4个大小各异的堆,以及大对象堆。
我想知道每个堆的作用及通常存储哪些内容的解释。
我在使用dotmemory分析一个Windows Forms应用程序的内存使用情况时,注意到对于我的应用程序,有0-4个大小各异的堆,以及大对象堆。
我想知道每个堆的作用及通常存储哪些内容的解释。
其他答案似乎忽略了堆和代之间的区别。我不明白为什么商业分析工具会混淆这两个概念,所以我强烈怀疑实际上是堆而不是代。
当CLR GC使用服务器模式时,它为进程亲和掩码中的每个逻辑处理器创建一个单独的堆。这种拆分主要是为了提高分配的可伸缩性,并在并行GC中执行。这些是单独的内存区域,但你当然可以在堆之间具有对象引用,并将它们视为单个逻辑堆。
因此,假设您有四个逻辑处理器(例如启用HyperThreading的i5 CPU),则在服务器GC下会有四个堆。
大对象堆有一个不幸、令人困惑的名称。它不是与每个处理器堆相同意义上的堆。它是在包含大型对象的多个内存区域之上的逻辑抽象。
在管理对象方面,有三个小对象堆(SOH)和一个大对象堆(LOH)。
大对象堆(LOH)
大于85KB的对象将直接进入LOH。如果您有太多的大对象,则存在一些风险。这是另一个讨论话题,有关详细信息,请查看大对象堆的危险性。
小对象堆(SOH):Gen0、Gen1、Gen2
垃圾收集器使用巧妙的算法仅在需要时执行垃圾收集。完整的垃圾回收过程是一项昂贵的操作,不应该经常发生。因此,它将其SOH分成三个部分,并且正如您已经注意到的每个代都有指定的内存量。
每个小对象(<85KB)最初都会进入Gen0。当Gen0已满时,垃圾回收仅针对Gen0执行。它检查所有在Gen0中的实例,并清除/释放任何不必要对象(非引用,超出作用域或已处理的对象)使用的内存。然后将所有所需(正在使用)实例复制到Gen1。// Perform a collection of generation 0 only.
GC.Collect(0);
这样,垃圾收集器首先清除为短生命周期实例分配的内存(不可变字符串、方法或较小作用域中的变量)。
当GC在一个阶段持续执行此操作时,Gen1会溢出。然后它对Gen1执行相同的操作。它清除Gen1中所有不必要的内存,并将所有所需的内存复制到Gen2中。
当您手动执行以下操作时,会发生上述过程(不需要手动调用)
// Perform a collection of all generations up to and including 1.
GC.Collect(1);
当垃圾回收在一个阶段一直执行此操作时,如果第二代堆溢出,它会尝试清理第二代堆。
即使您手动执行以下操作(不需要手动执行),以上过程也会发生。
// Perform a collection of all generations up to and including 2.
GC.Collect(2);
如果需要从Gen1复制到Gen2的内存量大于Gen2中可用的内存量,则GC会抛出内存不足异常。