使用 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 只保證 **解碼後的像素** 獨立於來源串流。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 關閉,檔案鎖定釋放,記憶體僅保留解碼後像素
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);
}
| 選項 | 行為 | 適用場景 |
|---|---|---|
| Default | 延遲解碼,串流需保持開啟 | 串流生命週期 ≥ BitmapImage |
| OnLoad | EndInit 時完整解碼,串流可關閉 | **短暫串流 (FileStream/MemoryStream) 必須使用** |
| OnDemand | 首次存取像素時解碼 | 大圖僅需元資料時 |