You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:25:21