WPF应用传递相机采集的Bitmap时触发AccessViolationException异常
问题根源
- uEye SDK的
Camera.Memory.ToBitmap接口生成的Bitmap对象直接引用SDK内部分配的非托管图像内存,并未独立拷贝图像数据。这和从本地文件加载的Bitmap完全不同,文件加载的Bitmap拥有独立的内存空间,生命周期不受SDK影响。 - 你的代码执行顺序错误:
CloseZoomedView方法中先执行了cam.Close()释放相机资源,再抛出事件传递Bitmap。相机关闭时SDK会自动回收所有分配的图像内存,此时传递的Bitmap指向的内存地址已经失效,访问时自然触发AccessViolationException。
解决思路
方案1:调整执行顺序
优先完成所有Bitmap处理逻辑,再释放相机资源,修改CloseZoomedView的代码顺序即可:
void CloseZoomedView(bool isConf) { ZoomClosingArgs eArg = new ZoomClosingArgs() { IsConfirmed = isConf, RefImage = refImage, }; // 先触发事件,等所有订阅者处理完Bitmap再关相机 ClosingZoom?.Invoke(this, eArg); if (cam is object && cam.IsConnected) cam.Close(); }
该方案适合ClosingZoom事件的订阅者都是同步处理图像的场景,无需额外拷贝数据,性能最优。
方案2:深拷贝Bitmap与SDK内存解绑
如果需要异步处理图像、或者无法控制相机关闭时机,可以在获取到SDK生成的Bitmap后立刻做深拷贝,生成独立的Bitmap对象,后续完全使用拷贝后的对象,不受SDK生命周期影响:
// 修改FetchImage,返回独立拷贝的Bitmap public void FetchImage(out Bitmap image) { camera.Memory.GetActive(out int memID); camera.Memory.ToBitmap(memID, out Bitmap sdkBitmap); // 深拷贝生成独立内存的Bitmap image = new Bitmap(sdkBitmap); // 释放SDK生成的原始Bitmap sdkBitmap.Dispose(); }
该方案通用性最强,不需要调整业务流程,仅增加了一次图像拷贝的开销,对常规分辨率的图像来说性能影响可以忽略。
注意事项
System.Drawing.Bitmap属于非托管资源,无论使用哪种方案,处理完图像后都要主动调用Dispose方法释放资源,避免内存泄漏。- 如果后续处理是在WPF上下文执行,也可以直接将拷贝后的图像转为
BitmapSource使用,完全规避System.Drawing的依赖。
内容的提问来源于stack exchange,提问作者MarcMan
相关产品推荐
相关产品推荐

