返回变量访问器时出现C#"Out of Memory Exception"

use*_*447 1 c# garbage-collection bitmap computer-vision

当我尝试创建一个Bitmap并通过"get"访问器返回它时,我得到一个Out Of Memory Exception.位图的大小为640x480,深度为Int32.

我怀疑C#垃圾收集器无法删除这些旧的位图,因为它们是在我的变量的访问器中返回的.我有超过2GB的可用空间,所以我不认为这个"小"图像占用太多内存.不幸的是,由于线程锁定问题,我必须重新创建Bitmap(在线程之间锁定图像时出现问题)代码如下:

public Bitmap LiveFrame { get { return GetFrame(500); } }
Run Code Online (Sandbox Code Playgroud)

.....

private Bitmap GetFrame(int timeout)
{
   Bitmap ret = null;
   //CLEyeCameraGetFrame places image data into this._PrivateBitmap
   bool success = CLEyeCameraGetFrame(_Camera, _PtrBmpPixels, timeout);  

   if(success) 
     ret = new Bitmap(this._PrivateBitmap);
    return ret;
}
Run Code Online (Sandbox Code Playgroud)

关于非托管代码的注意事项:CLEyeCameraGetFrame位于非托管DLL中.我在代码中使用Marshal.AllocHGlobal分配_PtrBmpPixels,并且在关闭应用程序时释放之前不要触摸它._PtrBmpPixels用于通过其接受IntPtr参数"scan0"的构造函数创建Bitmap _PrivateBitmap.因此,每当通过CLEyeCameraGetFrame更新_PtrBmpPixels时,_PrivateBitmap也会更新.

我尝试通过在重用之前处理PcitureBox位图来解决这个问题,但这打破了PictureBox的显示.我有两个线程更新两个不同的PictureBox/ImageBoxes:

lock (_CameraLocker)
{
  if (_VideoPlaying)
  {
    try{
         if (pbLiveFeed.Image != null)
            pbLiveFeed.Image.Dispose();

         pbLiveFeed.Image = _Camera.LiveFrame;
         pbLiveFeed.Invalidate();
       }catch (Exception ex) { }
}
Run Code Online (Sandbox Code Playgroud)

....

lock (_CameraLocker)
{
   try{
        if (ibProcessed.Image != null)
          ibProcessed.Image.Dispose();
        procImage = new Image<Bgra, Int32>(_Camera.LiveFrame);
        procImage.Draw(new Rectangle(10, 20, 20, 15), new Bgra(1.0, 1.0, 1.0, 1.0), 5);

        ibProcessed.Image = procImage;
      }catch (Exception ex) { }
}
Run Code Online (Sandbox Code Playgroud)

垃圾收集可能是导致这种情况的原因吗?从get访问器返回一个新的对象是不安全的?

Han*_*ant 5

你问题中唯一真正的线索是缺少什么.你从来没有说过"我确保在使用它之后处理位图".在.NET编程中,您可以轻松忽略哪些内容,但在使用位图时会出现字节.

Bitmap类是围绕由GDI +创建的非托管资源的非常小的包装类.实际的位图像素存储在非托管内存中.这就是为什么该类有一个Dispose()方法,它释放非托管内存分配.垃圾收集器可以帮助你自动释放这些内存,Bitmap对象太小,不足以引起垃圾收集,足以跟上程序消耗非托管内存的速度.oom-kaboom就是结果.

您需要查看其余代码并查看如何使用LiveFrame属性.并确保返回的位图正在处理.例如,如果将其分配给PictureBox.Image属性,则必须在分配之前处置旧图像.