当我的 ListBox 中有图像时,为什么会出现 OutOfMemoryException?

Why do I get an OutOfMemoryException when I have images in my ListBox?(当我的 ListBox 中有图像时,为什么会出现 OutOfMemoryException?)

本文介绍了当我的 ListBox 中有图像时,为什么会出现 OutOfMemoryException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的自定义库中显示存储在 Windows Phone 8 照片文件夹中的所有图像,该库使用 ListBox 来显示图像.

I want to display all images stored in the Windows Phone 8 photo folder in my custom gallery which uses a ListBox for displaying the images.

ListBox代码如下:

    <phone:PhoneApplicationPage.Resources>
        <MyApp:PreviewPictureConverter x:Key="PreviewPictureConverter" />
    </phone:PhoneApplicationPage.Resources>

    <ListBox Name="previewImageListbox" VirtualizingStackPanel.VirtualizationMode="Recycling">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel CleanUpVirtualizedItemEvent="VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1">
                </VirtualizingStackPanel>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Image Source="{Binding Converter={StaticResource PreviewPictureConverter}}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
     </ListBox>

使用以下转换器:

public class PreviewPictureConverter : System.Windows.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        PreviewImageItem c = value as PreviewImageItem;
        if (c == null)
            return null;
        return c.ImageData;
    }

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

图像存储在自定义类中:

Images are stored in a custom class:

class PreviewImageItem
{
    public Picture _picture = null;
    public BitmapImage _bitmap = null;

    public PreviewImageItem(Picture pic)
    {
        _picture = pic;
    }

    public BitmapImage ImageData 
    {
        get
        {
            System.Diagnostics.Debug.WriteLine("Get picture " + _picture.ToString());
            _bitmap = new BitmapImage();
            Stream data = _picture.GetImage();
            try
            {
                _bitmap.SetSource(data); // Out-of memory exception (see text)
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Exception : " + ex.ToString());
            }
            finally
            {
                data.Close();
                data.Dispose();
                data = null;
            }

            return _bitmap;
        }
    }
}

以下代码用于设置ListBox数据源:

The following code is used to set the ListBox data source:

private List<PreviewImageItem> _galleryImages = new List<PreviewImageItem>();

using (MediaLibrary library = new MediaLibrary())
{
    PictureCollection galleryPics = library.Pictures;
    foreach (Picture pic in galleryPics)
    {
        _galleryImages.Add(new PreviewImageItem(pic));
    }

    previewImageListbox.ItemsSource = _galleryImages;
};

最后是清理"代码:

private void VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1(object sender, CleanUpVirtualizedItemEventArgs e)
{
    PreviewImageItem item = e.Value as PreviewImageItem;

    if (item != null)
    {
        System.Diagnostics.Debug.WriteLine("Cleanup");
        item._bitmap = null;
    }
}

所有这些都可以正常工作,但是在几张图片之后代码会因 OutOfMemoryException 而崩溃(尤其是在快速滚动时).VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1 方法在 ListBox 滚动时被定期调用(例如,每 2 或 3 个列表框条目).

All this works fine but the code crashes with an OutOfMemoryException after a few images (especially when scrolling fast). The method VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1 is called regulary (e.g. every 2 or 3 listbox entries) when the ListBox is scrolled.

这个示例代码有什么问题?

What's wrong with this sample code?

为什么没有释放内存(足够快)?

Why is memory not freed (fast enough)?

推荐答案

哦,我最近花了一整天的时间来完成这个工作!

Oh, I recently killed whole day to make this working!

所以解决办法是:

使您的图像控件免费资源.所以设置

Make your Image control free resources. So set the

BitmapImage bitmapImage = image.Source as BitmapImage;
bitmapImage.UriSource = null;
image.Source = null;

如前所述.

确保在列表的每个项目上虚拟化 _bitmap.您应该按需加载它(LongListSelector.Realized 方法)并且您必须销毁它!它不会自动收集,而且 GC.Collect 也不起作用.空引用也不起作用:(但这里是方法:制作 1x1 像素文件.将其复制到程序集中并从中生成资源流,以使用 1x1 像素空白处理您的图像.将自定义 dispose 方法绑定到 LongListSelector.UnRealized 事件(e.Container 处理您的列表项).

Make sure you virtualize _bitmap on every item of the list. You should load it on demand (LongListSelector.Realized method) and you have to destroy it! It won't going to collect automatically and GC.Collect doesn't work either. Null reference is not working too :( But here is the method: Make 1x1 pixel file. Copy it into assembly and make resource stream from it to dispose your images with 1x1 pixel blank. Bind custom dispose method to LongListSelector.UnRealized event (e.Container handles your list item).

public static void DisposeImage(BitmapImage image)
{
    Uri uri= new Uri("oneXone.png", UriKind.Relative);
    StreamResourceInfo sr=Application.GetResourceStream(uri);
    try
    {
        using (Stream stream=sr.Stream)
        {
            image.DecodePixelWidth=1; //This is essential!
            image.SetSource(stream);
        }
    }
    catch { }
}

在 LongListSelector 中为我工作,有 1000 张图像,每张 400 宽.

Working for me in LongListSelector with 1000 images 400 width each.

如果您错过了数据收集的第 2 步,您可以看到良好的结果,但在滚动 100-200 个项目后内存溢出.

If you miss the 2 step with the data collection you can see the the good results but the memory overflows after 100-200 items scrolled.

这篇关于当我的 ListBox 中有图像时,为什么会出现 OutOfMemoryException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:当我的 ListBox 中有图像时,为什么会出现 OutOfMemoryException?

基础教程推荐