【问题标题】:What's the meaning of 'Free' block of Large object heap when dump with WinDbg使用 WinDbg 转储时,大对象堆的“空闲”块是什么意思
【发布时间】:2023-03-06 10:36:01
【问题描述】:

我正在调查 PerfMon 和 WinDbg 的内存泄漏问题。我注意到“大内存堆”计数器从 10MB 增加到 37MB。强制 GC 后,它只能减少到 28MB。

(无论我重复多少次操作(create/destroy),GC后大对象堆稳定在28MB)。

我想知道哪些对象会导致泄漏问题,因此我使用 '!Dumpheap -min 85000' 命令运行 WinDbg。捕获了两张快照,第一张是在内存泄漏之前完成的;第二个是内存泄漏后:

之前:

       MT    Count    TotalSize Class Name
 6f39fb08        1        89024 System.String
 6f3a4aa0        1       107336 System.Byte[]
 6f356d84        2       262176 System.Object[]
 00360e4c        1       350392 System.Collections.Generic.Dictionary`2+Entry[Int64,Int32][]
 6f3a2a94        3       592584 System.Int32[]
 00360c24        1       727072 System.Collections.Generic.Dictionary`2+Entry[String,Int64][]
 0bc78b34        4      2754488 System.Collections.Generic.Dictionary`2+Entry[Int64, AccountNode][]
 00730260       10      5375572      Free

之后:

       MT    Count    TotalSize Class Name
 6f39fb08        1        89024 System.String
 6f3a4aa0        1       107336 System.Byte[]
 6f3a55d8        2       202080 System.Collections.Hashtable+bucket[]
 6f356d84        2       262176 System.Object[]
 00360e4c        1       350392 System.Collections.Generic.Dictionary`2+Entry[Int64,Int32][]
 00360c24        1       727072 System.Collections.Generic.Dictionary`2+Entry[String,Int64][]
 6f3a2a94        4       738008 System.Int32[]
 6cf02838        1       872488 System.Collections.Generic.Dictionary`2+Entry[[MS.Internal.ComponentModel.PropertyKey, WindowsBase],[MS.Internal.ComponentModel.DependencyPropertyKind, WindowsBase]][]
 0bc78b34        4      2754488 System.Collections.Generic.Dictionary`2+Entry[Int64, AccountNode][]
 00730260       14     21881328      Free
 Total 31 objects

对比这两个快照,最大的区别是'Free'的大小。它的大小增加了近 16MB。 谁能告诉我“免费”是什么意思,是免费空间吗?增加是由碎片引起的吗?

根据this article,“大对象堆大小”性能计数器似乎包括可用空间。 所以在我的情况下,大对象堆上没有太多的内存泄漏,只有 2MB (= 28 - 10 -16),对吧?

【问题讨论】:

  • 这不是泄漏。这个是正常的。不要不要调用GC.Collect(),这是非常有害的。在您的程序开始使用过多的内存或内存或因 OOM 崩溃之前,不要追逐“泄漏”。 37MB 是花生。通过 CLR 阅读 Richter 的 C# 之类的好书自学。
  • 感谢您的回复。我同意你的观点,我们不应该在产品代码中调用 GC.Collect()。我不明白为什么不追查“泄漏”问题?据我所知,尽可能多的“垃圾”留在堆中,发生了尽可能多的 GC。在我看来,我们应该追逐它并减少不必要的refrenent(即unregist event),这可能会导致内存泄漏问题。

标签: c# memory-leaks windbg


【解决方案1】:

FREE 表示堆上的一块未使用的内存。 LOH 上的空闲块是预期的,因为 LOH 永远不会被压缩。相反,为 LOH 保留了一个可用空间列表。正常 GC 堆上的 FREE 块,除了少数例外,表示由于对象固定导致的碎片。当 GC 遇到 pinned 对象时,段的压缩将停止,未使用对象消耗的内存被标记为 FREE。您在 LOH 上看到的内容是正常的。请记住,LOH 永远不会被压缩,分配给 LOH 的内存段永远不会被释放,因此 LOH 永远不会收缩。

【讨论】:

  • 这个。大型对象堆最成问题的部分是缺乏压缩,这可能(如果您无意滥用它)导致堆碎片,这与您的硬盘驱动器发生的情况基本相同。
【解决方案2】:

大对象堆的意思是well explained here

大对象是大小大于 85kb 的对象,存储在该区域中,并且仅在第 2 代将被回收时才被收集。

【讨论】:

  • @Devil,感谢您的回复。但是我不是问关于“大对象堆”的问题,而是问 WinDbg 中显示的“免费”项目。
  • 应用程序执行期间的GC会分配和释放对象,因此堆会增长,但出于性能原因不会收缩到每次释放。这样做,应用程序可以为新对象获得足够的空间,而无需分配额外的内存。 GC 内部机制有时会回收部分未使用的堆以缩小它。我认为 FREE 是对象大小总和与当前分配的堆之间的差异。
  • 答案中的链接已失效
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-10
  • 2011-05-09
  • 2011-06-12
相关资源
最近更新 更多