在WPF中如何处理Listbox中的图像(内存泄漏)

5

我有一个ListBox,其中包含许多图像(通过数据模板完成)。这些图像是通过设置项源来创建的:

<Image x:Name="ItemImage" Source="{Binding ImageUrl}"/> 

然后使用列表框的Items.Clear()方法清除它们。通过使用列表框的Items.Add方法添加新图像。然而,内存使用量会不断增加。尽管显示的是相同的300多个小图像,但内存似乎永远不会被释放。应用程序开始使用约40兆字节,然后迅速上升到700兆字节。如何释放所有这些图像使用的内存?编辑:我忘记提到一件事,即这些大约4-5k大小的图像是通过网络加载的。缓存是否对此负责?显示12张图片会消耗大约10兆字节的内存,这大约是文件大小的100倍。
2个回答

4

除非您在加载图像时执行了任何不寻常的操作(例如使用自制的图像加载程序等),否则当没有任何引用它们时,GC应该会将它们清除。

您是否在其他地方保留了对数据的引用?请记住,事件和事件处理程序有时会“欺骗”垃圾收集器认为对象仍在使用中:

MyObject obj = new MyObject();
obj.TheEvent += new EventHandler(MyHandler);
obj = null;
// Now you might think that obj is set for collection but it 
// (probably - I don't have access to MS' .NET source code) isn't 
// since we're still listening to events from it.

不确定这是否适用于您,但如果我是您,我会检查这个地方。

此外,如果您有访问分析器(例如AQTime或类似工具),那么通过它运行代码可能会给您一些提示。

您还可以尝试查看从磁盘加载图像与从嵌入到程序集中的资源加载图像是否有任何区别。


4
不如一开始就不使用那么多内存呢?
(注:以下段落和代码摘自这个答案。)
问题的一部分是它在每个图像中加载完整的图像。您必须使用IValueConverter通过在BitmapImage上设置DecodePixelWidth或DecodePixelHeight属性来打开每个图像的缩略图大小。这是我在我的一个项目中使用的示例...
class PathToThumbnailConverter : IValueConverter {
    public int DecodeWidth {
        get;
        set;
    }

    public PathToThumbnailConverter() {
        DecodeWidth = 200;
    }

    public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
        var path = value as string;

        if ( !string.IsNullOrEmpty( path ) ) {

            FileInfo info = new FileInfo( path );

            if ( info.Exists && info.Length > 0 ) {
                BitmapImage bi = new BitmapImage();

                bi.BeginInit();
                bi.DecodePixelWidth = DecodeWidth;
                bi.CacheOption = BitmapCacheOption.OnLoad;
                bi.UriSource = new Uri( info.FullName );
                bi.EndInit();

                return bi;
            }
        }

        return null;
    }

    public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
        throw new NotImplementedException();
    }

}

您可能还需要考虑在Binding中使用IsAsync=True,以便转换器在后台线程上调用。


1
甚至更好的是 - 如果存在嵌入式缩略图,可以使用它,这样您甚至不需要读取整个文件并调整大小... 查找BitmapFrame.Thumbnail。 - Filip Skakun
我看到的问题是,这些缩略图通常带有黑色或白色边框,这并不总是很好看。我想这就是为什么大多数图片浏览器似乎都要建立自己的缩略图库的原因。 - Filip Skakun
这样,浏览器就可以控制缩略图的大小。 - Joel B Fant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接