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

解決 WPF BitmapImage 設定 DecodePixelWidth 後記憶體未釋放問題

     編輯:ASP.NET 基礎

問題現象

使用 MemoryStream 載入圖片並設定 DecodePixelWidth=100 期望只解碼縮圖,但 **MemoryStream 內的原始位元組陣列仍長駐記憶體**,直到 `BitmapImage` 被 GC 回收。大量載入 (如 1000 張) 會導致記憶體暴增。

錯誤寫法

var bitmap = new BitmapImage();
bitmap.BeginInit();
using (var stream = new MemoryStream(File.ReadAllBytes(path))) {
    bitmap.StreamSource = stream;
    bitmap.DecodePixelWidth = 100;
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.EndInit();
    bitmap.Freeze();
}
// stream Dispose 後,bitmap 仍持有原始資料參考!

根本原因

  • BitmapCacheOption.OnLoad 只保證 **解碼後的像素** 獨立於來源串流。
  • 但 `BitmapImage` 內部仍保留對 **來源串流資料的參考** (用於後續可能的重新解碼/元資料讀取)。
  • `MemoryStream` 以位元組陣列為後備,`Dispose` **不會釋放陣列**,陣列隨 `BitmapImage` 存活。

正確解法:改用 FileStream

var bitmap = new BitmapImage();
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) {
    bitmap.BeginInit();
    bitmap.StreamSource = fs;
    bitmap.DecodePixelWidth = 100;          // 只解碼縮圖
    bitmap.CacheOption = BitmapCacheOption.OnLoad; // 關鍵:載入後關閉串流
    bitmap.EndInit();
    bitmap.Freeze();                        // 跨執行緒使用必須 Freeze
}
// using 結束,FileStream 關閉,檔案鎖定釋放,記憶體僅保留解碼後像素

為什麼 FileStream 可行?

  • `FileStream` 直接對應檔案控制代碼,`Close` 釋放系統資源,`BitmapImage` 內部參考失效但像素已快取。
  • 原始檔案資料**不在 managed heap**,不佔用 .NET 記憶體。

完整非同步載入範例 (背景執行緒 + UI 更新)

public async Task LoadThumbnailAsync(string path, Image target, int pixelWidth = 100) {
    var bitmap = new BitmapImage();
    await Task.Run(() => {
        using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) {
            bitmap.BeginInit();
            bitmap.StreamSource = fs;
            bitmap.DecodePixelWidth = pixelWidth;
            bitmap.CacheOption = BitmapCacheOption.OnLoad;
            bitmap.EndInit();
            bitmap.Freeze();
        }
    });
    await Application.Current.Dispatcher.InvokeAsync(() => target.Source = bitmap);
}

補充:BitmapCacheOption 對照

選項行為適用場景
Default延遲解碼,串流需保持開啟串流生命週期 ≥ BitmapImage
OnLoadEndInit 時完整解碼,串流可關閉**短暫串流 (FileStream/MemoryStream) 必須使用**
OnDemand首次存取像素時解碼大圖僅需元資料時
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved