WPF文档查看器内存泄漏致图片消失问题求助
解决WPF文档查看器导出时BitmapImage内存飙升及OutOfMemoryException问题
问题根源
当前代码用ImageSourceConverter加载图片,默认创建的BitmapImage会将完整图片数据缓存到内存中,且未配置资源释放策略,多次导出时内存无法及时回收,导致从200MB飙升至700MB,最终触发OutOfMemoryException。
优化方案
1. 手动配置BitmapImage的缓存与解码选项
直接创建BitmapImage并设置BitmapCacheOption.OnLoad,加载完成后立即释放文件资源;同时按实际显示尺寸解码图片,避免加载原始大尺寸图片占用过多内存。
修改后的BuildImage方法示例:
public Image BuildImage(string path, double left, double top, double right, double bottom, double scaleWidth, double scaleHeight) { Image _tempImage = new Image(); try { using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) { BitmapImage bitmap = new BitmapImage(); bitmap.BeginInit(); // 加载完成后释放文件句柄,不缓存到内存 bitmap.CacheOption = BitmapCacheOption.OnLoad; // 按实际显示尺寸解码,减少内存占用 bitmap.DecodePixelWidth = (int)((right - left) * scaleWidth); bitmap.DecodePixelHeight = (int)((top - bottom) * scaleHeight); bitmap.StreamSource = fs; bitmap.EndInit(); // 冻结BitmapImage,允许GC更高效回收,同时线程安全 bitmap.Freeze(); _tempImage.Source = bitmap; } _tempImage.HorizontalAlignment = System.Windows.HorizontalAlignment.Left; _tempImage.VerticalAlignment = System.Windows.VerticalAlignment.Bottom; _tempImage.SetValue(FixedPage.LeftProperty, left * scaleWidth); _tempImage.SetValue(FixedPage.BottomProperty, bottom * scaleHeight); _tempImage.Width = (right - left) * scaleWidth; _tempImage.Height = (top - bottom) * scaleHeight; _tempImage.Stretch = Stretch.UniformToFill; } catch (Exception e) { MessageBox.Show("Erro ao carregar imagem (1): " + e.Message); return null; } return _tempImage; }
2. 导出完成后强制清理内存
导出流程结束后,解除所有不再使用的Image对象引用,触发垃圾回收释放内存:
// 导出完成后调用此方法 public void CleanupAfterExport() { // 先解除所有导出用Image对象的引用(比如清空相关集合) // 示例:假设exportImages是存储导出用Image的集合 // exportImages.Clear(); // 触发垃圾回收 GC.Collect(); GC.WaitForPendingFinalizers(); // 再次回收,确保Finalizer处理完资源 GC.Collect(); }
注意:仅在导出完成后调用,不要频繁触发GC,避免影响性能。
3. 避免重复加载相同图片
如果文档中有重复图片,可创建一个图片缓存字典,键为图片路径,值为冻结后的BitmapImage,重复使用时直接取缓存,避免重复加载占用内存:
private static Dictionary<string, BitmapImage> _imageCache = new Dictionary<string, BitmapImage>(); public BitmapImage GetCachedImage(string path, int decodeWidth, int decodeHeight) { if (_imageCache.TryGetValue(path, out var bitmap)) { return bitmap; } using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) { BitmapImage bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.DecodePixelWidth = decodeWidth; bitmap.DecodePixelHeight = decodeHeight; bitmap.StreamSource = fs; bitmap.EndInit(); bitmap.Freeze(); _imageCache.Add(path, bitmap); return bitmap; } }
注意:如果图片文件可能被修改,需在缓存时加入文件最后修改时间,或者提供缓存清理方法。
验证方法
按上述方案修改后,重复执行导出操作,对比内存变化(参考你提供的内存对比图),如果内存不再持续飙升,说明优化生效。
内容的提问来源于stack exchange,提问作者Pablo Sarturi
相关产品推荐
相关产品推荐

