嗨,我创建了一个窗口在wpf。这是一个打印预览屏幕。它在DocumentViewer中显示(FixedDocumentSequence).FixedDocumentSequence是由Flow Document用动态绑定创建的。
单窗口占用近500MB。每次内存泄漏约100MB。打开超过5或10次内存溢出1 gb。
I在STA线程(不是UI线程)中打开窗口。执行Dispatcher关闭方法。但有些对象不能从记忆中释放出来。(调度器关闭后内存对象还活着吗?)
我已经使用了WinDbg来检查内存泄漏,Flow文档部分仍然显示。
!dumpheap -stat
检查对象的根。但是它显示"找到0个唯一根"
!gcroot [address]
我的英语可能很差,无法理解问题的意思。
(问题1)你能给我一些解决内存泄漏的建议吗?
(另一个信息和问题:我想尝试在dispose方法中设置null。
GC终结器从另一个线程调用析构函数。因此,运行时不能看到对象的值,也不能在dispose方法中将值设置为null。
(问题2)我已经关闭了调度器。所以有必要在Dispose(bool Dispose)方法中实现任何东西吗?)
每次内存泄漏约100MB。
实际上那很好。可重现的内存泄漏应该很容易修复。
I在STA线程(不是UI线程)中打开窗口。
我不明白。如果您使用Application.Run()
,该线程将成为UI线程。
检查对象的根目录
哪些对象?你为什么选择它?
但是显示" Found 0 unique roots "
这意味着它符合垃圾收集的条件。下次垃圾回收器运行时,它很可能已经消失了。
我想尝试在dispose方法中设置null。
对于报告为"找到0个唯一根"的对象,这已经完成了。
但是,即使您将所有变量设置为null
,对象仍然会在那里。你只是不再有参考了。
GC终结器从另一个线程调用析构函数。
这是正常的。有一个专用的终结器线程。
所以运行时不能看到对象的值,也不能在dispose方法中将值设置为null。
你可以在终结器线程中设置变量为null
。所有线程都可以访问内存
所以有必要在Dispose(bool Dispose)方法中实现任何东西吗?)
如果不知道你的窗口使用了什么资源,这是很难判断的。
如何处理?
首先,找一个比WinDbg更好的工具。这可以用WinDbg来完成,但是需要付出很多努力。无论你使用什么工具:
- 运行有漏洞的应用程序
- 重现泄漏
- 强制垃圾收集(如果你不能这样做,实现一个按钮)
- 拍摄快照(基本上是完整的
!dumpheap
) - 尽可能重复泄漏7次(否则5或3次)
- 再次强制垃圾回收
- 再次快照
- 比较两个快照(创建diff)
在快照diff中,您现在可以查找具有7的倍数的新对象(例如21,70,91,…)。这些是泄露的信息。检查这些GC根。
当您重复泄漏7次时,不太可能泄漏5、6、8或9个对象。我选择一个素数或至少是奇数,因为2、4和8的倍数在计算机程序中自然出现。
在WinDbg中对!dumpheap
的输出进行区分是困难的。您可能需要.logopen
来捕获所有输出。也许你最终会为日志文件编写自己的解析器。
我看到很多开发人员使用Jetbrains Resharper。一些许可证包括dotMemory。我对它很满意,它把工作完成了。