当我尝试创建一个Bitmap并通过“get”访问器返回时,我得到了Out Of Memory Exception。位图的大小为640x480,深度为Int32。
我怀疑C#垃圾收集器无法删除这些旧的位图,因为它们是在我的变量的访问器中返回的。我有超过2GB的可用空间,所以我不认为这个“小”图像占用太多内存。不幸的是,由于线程锁定问题(Trouble with locking an image between threads),我必须新建Bitmap。代码如下:
public Bitmap LiveFrame { get { return GetFrame(500); } }
.....
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;
}
关于非托管代码的注意事项: 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) { }
}
...
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) { }
}
垃圾收集是否可能导致此问题?从get访问器返回一个新对象是不安全的吗?
答案 0 :(得分:5)
您问题中唯一真正的线索是缺少。你从来没有说过“我确保在使用它之后处理位图”。这是你在.NET编程中可以轻易忽略的东西,但是当你使用位图时它会变成字节。
Bitmap类是围绕由GDI +创建的非托管资源的非常小的包装类。实际的位图像素存储在非托管内存中。这就是为什么该类有一个Dispose()方法,它释放非托管内存分配。垃圾收集器可以帮助您自动释放这些内存,Bitmap对象太小,不足以引起垃圾收集,足以跟上程序消耗非托管内存的速度。 oom-kaboom就是结果。
您需要查看其余代码,看看如何使用LiveFrame属性。并确保返回的位图正在处理。例如,如果将其分配给PictureBox.Image属性,则必须在分配之前处置旧图像。