WPF CreateBitmapSourceFromHBitmap()内存泄漏
我需要逐个像素地绘制图像,并将其显示在WPF中。 我正在尝试通过使用System.Drawing.Bitmap
然后使用CreateBitmapSourceFromHBitmap()
为WPF图像控件创build一个BitmapSource
。 我有一个内存泄漏的地方,因为当CreateBitmapSourceFromBitmap()
被重复调用时,内存使用率上升,直到应用程序结束时不下降。 如果我不调用CreateBitmapSourceFromBitmap()
内存使用情况没有明显的变化。
for (int i = 0; i < 100; i++) { var bmp = new System.Drawing.Bitmap(1000, 1000); var source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); source = null; bmp.Dispose(); bmp = null; }
我能做些什么来释放BitmapSource
内存?
MSDN指出,对于Bitmap.GetHbitmap()
: 您负责调用GDI DeleteObject方法释放GDI位图对象使用的内存。 所以使用下面的代码:
// at class level [System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); // your code using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(1000, 1000)) { IntPtr hBitmap = bmp.GetHbitmap(); try { var source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); } finally { DeleteObject(hBitmap) } }
我也用using
语句replace了你的Dispose()
调用。
每当处理非托pipe句柄时,使用“安全句柄”包装可能是一个好主意:
public class SafeHBitmapHandle : SafeHandleZeroOrMinusOneIsInvalid { [SecurityCritical] public SafeHBitmapHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) { SetHandle(preexistingHandle); } protected override bool ReleaseHandle() { return GdiNative.DeleteObject(handle) > 0; } }
构build一个就像你表面处理(理想情况下你的API永远不会公开IntPtr,他们总是会返回安全句柄):
IntPtr hbitmap = bitmap.GetHbitmap(); var handle = new SafeHBitmapHandle(hbitmap , true);
像这样使用它:
using (handle) { ... Imaging.CreateBitmapSourceFromHBitmap(handle.DangerousGetHandle(), ...) }
SafeHandle基础为您提供自动一次性/终结器模式,您只需重写ReleaseHandle方法即可。
我有相同的要求和问题(内存泄漏)。 我实现了与标记为答案相同的解决scheme。 但是,尽pipe解决scheme有效,但对性能造成了令人难以接受的冲击。 运行在i7上,我的testing应用程序看到一个稳定的30-40%的CPU,200-400MB的RAM增加,垃圾收集器运行几乎每毫秒。
由于我在做video处理,所以我需要更好的性能。 我想出了以下内容,所以认为我会分享。
可重用的全局对象
//set up your Bitmap and WritableBitmap as you see fit Bitmap colorBitmap = new Bitmap(..); WriteableBitmap colorWB = new WriteableBitmap(..); //choose appropriate bytes as per your pixel format, I'll cheat here an just pick 4 int bytesPerPixel = 4; //rectangles will be used to identify what bits change Rectangle colorBitmapRectangle = new Rectangle(0, 0, colorBitmap.Width, colorBitmap.Height); Int32Rect colorBitmapInt32Rect = new Int32Rect(0, 0, colorWB.PixelWidth, colorWB.PixelHeight);
转换代码
private void ConvertBitmapToWritableBitmap() { BitmapData data = colorBitmap.LockBits(colorBitmapRectangle, ImageLockMode.WriteOnly, colorBitmap.PixelFormat); colorWB.WritePixels(colorBitmapInt32Rect, data.Scan0, data.Width * data.Height * bytesPerPixel, data.Stride); colorBitmap.UnlockBits(data); }
实现示例
//do stuff to your bitmap ConvertBitmapToWritableBitmap(); Image.Source = colorWB;
结果是一个稳定的10-13%的CPU,70-150MB的RAM,垃圾收集器只运行了两次,运行时间为6分钟。