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分钟。