首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WPF 循環載入圖片導致記憶體洩漏的三種解決方案

     編輯:關於.NET

場景:大量圖片依序載入形成動畫(如工業檢測、醫療影像)。若不當處理 BitmapImage,會導致非託管記憶體累積、最終 OutOfMemoryException。

方案一:Uri 直接載入(一般場景適用)

var src = new BitmapImage(new Uri(path, UriKind.Absolute));
image.Source = src;

簡單但無法控制快取與解碼時機,大量循環易爆記憶體。

方案二:Stream + BitmapCacheOption.OnLoad + Freeze(推薦)

var data = File.ReadAllBytes(path);
var ms = new MemoryStream(data);
var src = new BitmapImage();
src.BeginInit();
src.CacheOption = BitmapCacheOption.OnLoad; // 立即解碼,Stream 可立即關閉
src.StreamSource = ms;
src.EndInit();
src.Freeze(); // 讓 BitmapImage 可跨執行緒、不可變,利於 GC
ms.Close();
return src;

關鍵點:OnLoad 強制立即解碼像素資料到託管記憶體,Freeze() 釋放非託管資源參考。

方案三:System.Drawing.Bitmap 中轉 + DeleteObject(高解析度/攝影機影像)

適用於取得 byte[] 或 IntPtr 的高效能攝影機 SDK:

[DllImport("gdi32.dll", SetLastError = true)]
private static extern bool DeleteObject(IntPtr hObject);

private BitmapSource ToBitmapSource(System.Drawing.Bitmap bmp)
{
    try
    {
        var hBitmap = bmp.GetHbitmap();
        var src = Imaging.CreateBitmapSourceFromHBitmap(
            hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        DeleteObject(hBitmap); // 關鍵:釋放 GDI 物件
        return src;
    }
    catch { return null; }
}

// 使用
var ms = new MemoryStream(data);
var gdiBmp = new System.Drawing.Bitmap(ms);
var src = ToBitmapSource(gdiBmp);
ms.Close();
gdiBmp.Dispose(); // 釋放 Managed Bitmap
return src;

比較總結

方案適用場景記憶體控制跨執行緒
Uri 直接少量、靜態圖片弱否
Stream + OnLoad + Freeze大量循環、檔案載入強是
GDI+ 中轉 + DeleteObject高解析度、攝影機 SDK、byte[] 來源最強是

額外建議

  • 使用 GC.Collect() 只作最後手段,優先靠 Freeze、Dispose、DeleteObject 釋放非託管資源。
  • 若圖片尺寸固定,考慮 WriteableBitmap 重複使用像素緩衝區。
  • 啟用 BitmapCacheOption.OnDemand 並手動 DecodePixelWidth/Height 限制解碼尺寸。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved