如何通过windbg从“System.Drawing.Bitmap”中提​​取图像到文件?

时间:2013-11-14 10:52:34

标签: .net memory-leaks windbg

我有一个内存转储文件,似乎是'System.Drawing.Bitmap'对象的内存泄漏。 我有这种类型的多个对象!gcroot无法帮助我识别泄漏的位置。

示例输出:

  

DOMAIN(0071D148):手柄(销接):1513e8:根:   03335250(System.Object的[]) - > 0248e8ec(System.Drawing.Bitmap)

我有一个想法是将内存转储中的图像提取到图像文件中,然后,当我可以看到泄漏的图像是什么时,我可以检查创建该特定位图的源代码。

那么,如何将内存写入我可以在图像查看器中打开的文件并查看Bitmap对象保存的图像呢?

另外,如果您有其他想法如何识别泄漏源,我很乐意听到它们。

由于

2 个答案:

答案 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似乎仍然可能。

步骤:

  1. !dumpheap -short -type System.Drawing.Bitmap
  2. !do <address>
  3. 查找属性nativeImage
  4. 的偏移量
  5. dps在该IntPtr上(等于dps poi(<address>+<offset>)?)为您提供类型
  6. dt <address> <type> - &gt; InternalBitmap属性
  7. dt <internalAddress> <internalType> - &gt; Bmp财产
  8. dt <bmpAddress> <bmpType>提供Scan0属性,即起始地址
  9. 我无法跟进如何计算位图的大小,这是执行.writemem所需的。有宽度和高度,可能PixelFormat可用于计算每像素的位数。