13

我是 C# 的新手。我必须在工作线程中反复刷新 GUI 图片框。图像是从使用 GetImage 方法轮询驱动程序的相机获取的,该方法检索要显示的图像。即使我使用指令“使用”分配位图并显式调用 GC,内存似乎也永远不会被释放。

工作线程是这样的:

   while (true)
    {
        // request image with IR signal values (array of UInt16)
        image = axLVCam.GetImage(0);
        lut = axLVCam.GetLUT(1);
        DrawPicture(image, lut);
        //GC.Collect();

    }

虽然 DrawPicture 方法类似于

   public void DrawPicture(object image, object lut)
{

  [...]

    // We have an image - cast it to proper type
    System.UInt16[,] im = image as System.UInt16[,];
    float[] lutTempConversion = lut as float[];

    int lngWidthIrImage = im.GetLength(0);
    int lngHeightIrImage = im.GetLength(1);

    using (Bitmap bmp = new Bitmap(lngWidthIrImage, lngHeightIrImage)) {

      [...many operation on bitmap pixel...]

        // Bitmap is ready - update image control

        //SetControlPropertyThreadSafe(tempTxtBox, "Text", string.Format("{0:0.#}", lutTempConversion[im[160, 100]]));

        //tempTxtBox.Text = string.Format("{0:00000}", im[160, 100]);
        //System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
        pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
    }
}

问题出现了

pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());

事实上,评论那行代码,垃圾收集就可以正常工作。更好的是,问题似乎出在

System.Drawing.Image.FromHbitmap(bmp.GetHbitmap())

有什么建议可以解决这个内存泄漏?

非常感谢!

4

3 回答 3

19

Imageimplements IDisposable,因此您应该在不再需要时调用您创建Dispose的每个实例。Image您可以尝试在代码中替换此行:

pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());

有了这个:

if (pic.Image != null)
{
    pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());

这将在分配新图像之前处理前一个图像(如果有)。

于 2009-12-02T09:33:14.887 回答
8

问题是,您正在bmp使用 GetHbitmap 制作 GDI 位图,根据 msdn:

您负责调用 GDI DeleteObject 方法来释放 GDI 位图对象使用的内存。

然后 FromHbitmap 方法复制 GDI 位图;因此您可以在创建新图像后立即使用 GDI DeleteObject 方法释放传入的 GDI 位图。

所以基本上我会补充:

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

...

IntPtr gdiBitmap = bmp.GetHbitmap();

// Release the copied GDI bitmap
if (pic.Image != null)
{
    pic.Image.Dispose();
}

pic.Image = System.Drawing.Image.FromHbitmap(gdiBitmap);

// Release the current GDI bitmap
DeleteObject(gdiBitmap);

我不确定您是否需要 GDI 位图来执行某种转换。如果您不这样做,您可以将位图分配给 PictureBox 的 Image 属性,而忽略前一个解决方案:

// Since we're not using unmanaged resources anymore, explicitly disposing 
// the Image only results in more immediate garbage collection, there wouldn't 
// actually be a memory leak if you forget to dispose.
if (pic.Image != null)
{
    pic.Image.Dispose();
}

pic.Image = bmp;
于 2009-12-02T09:40:41.040 回答
3

有几种方法可以从 pbox 中释放图像。我强烈推荐的方式是不要使用pbox.Image = Image.FromFile.... 如果您不使用 FileStream 并且想从文件中读取它,请使用 BitMap 类。像这样:

Bitmap bmp = new Bitmap(fileName);
pbox.Image = bmp; // notice that we used bitmap class to initialize pbox.

...然后你想释放图像文件bmp.Dispose();
现在你可以删除、移动或任何你想要的文件。

于 2011-02-21T22:55:55.920 回答