首页 > 解决方案 > C# 中的 FlowDocument 内存问题(但 WinDbg gcroot 显示“找到 0 个唯一根”

问题描述

标签: wpfmemory-leakswindbgflowdocument

解决方案


每次内存泄漏大约 100MB。

其实这很棒。可重现的内存泄漏应该很容易修复。

我在 STA 线程(不是 UI 线程)中打开窗口。

我不明白。如果使用Application.Run(),该线程将成为 UI 线程。

我检查对象的根。

哪个对象?你为什么选择它?

但它显示“找到 0 个唯一根”</p>

这意味着它有资格进行垃圾收集。下次垃圾收集器运行时,它可能会消失。

我也想尝试在 dispose 方法中设置 null 。

对于报告为“找到 0 个唯一根”的对象,这已经完成。

但即使您将所有变量设置为null,对象仍然存在。你只是没有参考了。

GC 终结器从另一个线程调用析构函数。

这很正常。有一个专用的终结器线程。

所以运行时看不到对象值,也不能在 dispose 方法中将值设置为 null。

您可以将变量设置到null终结器线程内。可以从所有线程访问内存。

那么有必要在 Dispose(bool disposing) 方法中实现任何东西吗?)

在不知道您的窗口使用什么资源的情况下,这很难说。

如何进行?

首先,获得比 WinDbg 更好的工具。可以用WinDbg完成,但要费很大力气。无论您使用什么工具:

  1. 运行泄漏的应用程序
  2. 重现泄漏
  3. 强制进行垃圾收集(如果不能这样做,请执行一个按钮)
  4. 拍摄快照(基本上是完整的!dumpheap
  5. 如果可能,再次泄漏 7 次(否则 5 或 3 次)
  6. 再次强制垃圾回收
  7. 再拍一张
  8. 比较两个快照(创建差异)

在快照差异中,您现在可以查找具有 7 倍数的新对象(如 21、70、91,...)。这些是泄漏的。检查那些的 GC 根。

当您重现泄漏 7 次时,泄漏 5、6、8 或 9 个对象的可能性很小。我选择素数或至少是奇数,因为 2、4 和 8 的倍数在计算机程序中很自然地出现。

!dumpheap用WinDbg的输出做 diff是很困难的。您可能需要 a.logopen来捕获所有输出。也许你最终会为日志文件编写自己的解析器。

我看到很多开发人员使用 Jetbrains Resharper。一些许可证包括 dotMemory。我对此很满意,它完成了工作。


推荐阅读