我有一个内存转储文件,似乎是'System.Drawing.Bitmap'对象的内存泄漏。 我有这种类型的多个对象!gcroot无法帮助我识别泄漏的位置。
示例输出:
DOMAIN(0071D148):手柄(销接):1513e8:根: 03335250(System.Object的[]) - > 0248e8ec(System.Drawing.Bitmap)
我有一个想法是将内存转储中的图像提取到图像文件中,然后,当我可以看到泄漏的图像是什么时,我可以检查创建该特定位图的源代码。
那么,如何将内存写入我可以在图像查看器中打开的文件并查看Bitmap对象保存的图像呢?
另外,如果您有其他想法如何识别泄漏源,我很乐意听到它们。
由于
答案 0 :(得分:5)
System.Drawing.Bitmap是一个很小的托管对象。它包装由非托管GDI + api返回的句柄,存储在私有 nativeImage 字段中。从该句柄中查找位图数据是大海狩猎中的一项练习。也不是位图数据以任何方式与图像文件格式兼容,只有Bitmap :: Save()调用可以这样做,运行所需的图像编码器。
抓住这个想法。
对Bitmap对象存在内存问题,否则非常常见。太多的程序员忽略了Bitmap继承了IDisposable。您可以编写很多.NET程序,从不调用Dispose()或使用 using 语句,程序运行正常。垃圾收集器使他们免于麻烦。然而,Bitmap类是单一的.NET类,它不再起作用。问题是它很小。在触发垃圾收集之前,您可以创建数万个它们。通常不足以让垃圾收集器释放非托管GDI +句柄。结果,程序运行非常,使用大量非托管内存。当程序以32位模式运行时,很可能发生OOM崩溃。或者64位模式下的千兆字节提交大小
在Windbg迷路之前,请先仔细阅读该程序的源代码。并验证您是否可以将每个 Bitmap变量与相应的Dispose()调用或使用语句配对。注意诸如分配PictureBox.Image属性之类的事情,而不需要在前一个图像上调用Dispose()方法的代码。另外,.NET内存分析器是调试它的更好工具。
答案 1 :(得分:1)
如果您真的想这样做,dump all bitmaps from memory似乎仍然可能。
步骤:
!dumpheap -short -type System.Drawing.Bitmap
!do <address>
nativeImage
dps
在该IntPtr上(等于dps poi(<address>+<offset>)
?)为您提供类型dt <address> <type>
- &gt; InternalBitmap属性dt <internalAddress> <internalType>
- &gt; Bmp财产dt <bmpAddress> <bmpType>
提供Scan0属性,即起始地址我无法跟进如何计算位图的大小,这是执行.writemem
所需的。有宽度和高度,可能PixelFormat可用于计算每像素的位数。