由于固定的 GC 句柄导致内存泄漏/没有可见的 gc root

Memory leak because of pinned GC handles / no gc root visible

使用非托管 .net 组件时固定 GC 句柄的原因是什么?这种情况时常发生,而无需更改任何代码或其他内容。在调查这个问题时,我看到很多固定的 GC-Handles

这些句柄似乎在整个应用程序生命周期内都保留在内存中。在这种情况下,库是 GdPicture (14)。有什么方法可以调查 为什么 这些实例没有被清除?我到处都在使用 Dispose()/using,但在托管代码中找不到任何 GC 根。

非常感谢!

编辑

另一个奇怪的行为是,任务管理器显示应用程序使用了大约 6GB 内存,而内存分析器显示使用量为 400MB(红线是活动字节)

What is the reason for pinned GC handles when working with unmanaged .net components?

使用非托管代码时需要固定。它防止对象在垃圾回收期间被移动,以便非托管代码可以有一个指向它的指针。垃圾收集器将更新所有 .NET 引用,但不会更新非托管指针值。

Is there any way to investigate why those instances are not cleaned up?

没有。原因总是:代码中存在错误。您的代码(首先假设)或第 3 方库(经常使用库,很可能之前其他人已发现库中的泄漏)。

I'm using Dispose()/using everywhere

好像你漏掉了一个或者它没有使用一次性模式。

Another behaviour that is strange is, that the task manager shows that the application uses about 6GB ram, when the memory profiler shows the usage of 400MB (red line is live bytes)

.NET 内存分析器可能只显示内存的 .NET 部分 (400 MB),而忽略其余部分 (5600 MB)。

任务管理器对 .NET 不感兴趣。它主要关心 物理 RAM,这就是为什么任务管理器通常不是一个好的分析工具。你不想分析物理内存,你想分析虚拟内存。

要查找内存泄漏,请使用 Process Explorer 并显示“专用字节数”和“虚拟大小”列。 Process Explorer 还可以显示每个进程随时间变化的图表。

如何进行?

暂时忘掉非托管泄漏。使用具有拍摄内存快照功能的 .NET 探查器,并允许您查看内部的每个单独对象以及统计信息。

尝试找出以一致的方式制造更多泄漏所需的步骤。然后

  1. 拍一张快照
  2. 重复泄漏程序 10 次
  3. 拍一张快照
  4. 再重复泄漏程序 10 次
  5. 拍照

比较第 1 步和第 3 步的快照。检查托管类型是否为 10 的倍数。比较第 3 步和第 5 步的快照。再次检查同一类型。它必须是 10 的倍数。当您 运行 一个方法 10 次时,您不能泄漏 7 个对象。

根据对泄漏过程(调用哪些方法)和托管类型的内部知识,对使用受影响类型的地方进行代码审查。确保它被妥善处理或释放。