c#picturebox内存释放问题

pic*_*cio 9 c# memory-leaks memory-management picturebox

我是C#的新手.我必须在工作线程中重复刷新GUI图片框.从使用GetImage方法轮询驱动程序的摄像机获取图像,该方法检索要显示的图像.即使我使用指令"using"分配位图并显式调用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();

    }
Run Code Online (Sandbox Code Playgroud)

虽然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());
    }
}
Run Code Online (Sandbox Code Playgroud)

问题出现了

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

事实上,评论那行代码,垃圾收集工作就像它一样.更好的是,问题似乎与之相关

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

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

非常感谢!

Fre*_*örk 15

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

pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
Run Code Online (Sandbox Code Playgroud)

有了这个:

if (pic.Image != null)
{
    pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
Run Code Online (Sandbox Code Playgroud)

这将在分配新图像之前处理先前的图像(如果有的话).

  • 只是不要使用GetHbitmap(),没有意义.直接将bmp分配给Image属性.位图派生自Image. (2认同)

Yan*_*ton 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);
Run Code Online (Sandbox Code Playgroud)

我不确定你是否需要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;
Run Code Online (Sandbox Code Playgroud)