C#中计算机视觉场景下的内存泄漏问题求助
WPF BitmapSource 内存泄漏修复方案
问题根源
你的内存泄漏并非来自BitmapSource未释放,而是调用Imaging.CreateBitmapSourceFromHBitmap时,faceBitmap.GetHbitmap()/imageBitmap.GetHbitmap()会生成未托管的GDI位图句柄,这个句柄不会被.NET GC自动回收,必须手动调用Win32 API释放。
修复步骤
- 引入
DeleteObject方法用于释放GDI句柄(需添加System.Runtime.InteropServices引用) - 每次调用
GetHbitmap()后保存返回的IntPtr,创建BitmapSource后立即释放该句柄 - 重构重复的转换逻辑,减少冗余代码
修复后的完整代码
using System.Runtime.InteropServices; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; private static void UpdateResultingImage(bool onlyShowFace = false) { if ((imageBitmap == null && faceBitmap == null) || ResultingImage == null) { return; } // 处理人脸位图转换 if (faceBitmap != null) { // 清理旧BitmapSource的关联资源 if (faceBitmapSource != null) { faceBitmapSource.ClearValue(BitmapSource.CacheOptionProperty); faceBitmapSource = null; } IntPtr hBitmap = faceBitmap.GetHbitmap(); try { faceBitmapSource = Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); faceBitmapSource = ScaleBitmap(faceBitmapSource, ResultingImage.Width, ResultingImage.Height); } finally { // 强制释放未托管GDI句柄 DeleteObject(hBitmap); } } // 处理原图转换 if (imageBitmap != null) { // 清理旧BitmapSource的关联资源 if (imageBitmapSource != null) { imageBitmapSource.ClearValue(BitmapSource.CacheOptionProperty); imageBitmapSource = null; } IntPtr hBitmap = imageBitmap.GetHbitmap(); try { imageBitmapSource = Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); imageBitmapSource = ScaleBitmap(imageBitmapSource, ResultingImage.Width, ResultingImage.Height); } finally { // 强制释放未托管GDI句柄 DeleteObject(hBitmap); } } ResultingImage.Source = onlyShowFace ? faceBitmapSource : imageBitmapSource; } // 引入Win32 API释放GDI对象 [DllImport("gdi32.dll", EntryPoint = "DeleteObject")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DeleteObject(IntPtr hObject);
额外说明
- 无需手动调用
GC.Collect(),释放GDI句柄后,GC会自动回收BitmapSource的托管资源 - .NET Core/.NET 5+环境下,
CreateBitmapSourceFromHBitmap的行为一致,仍需手动释放HBitmap句柄 - 可将Bitmap转BitmapSource的逻辑封装为单独方法,进一步提升代码可维护性
内容的提问来源于stack exchange,提问作者Gabriel Alabi
相关产品推荐
相关产品推荐

