为什么我得到一个OutOfMemoryException当我在我的列表框的图片?(Why do I

2019-07-04 22:51发布

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

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();
    }
}

图像存储在一个自定义类:

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数据源:

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当被调用regulary(例如每2名或3列表框的条目) ListBox被滚动。

有什么不对的示例代码?

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

Answer 1:

哦,我最近被杀害整天做这个工作!

因此,解决办法是:

让你的图像控制的资源。 所以设置

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

因为它是前面提到的。

请确保您虚拟化_bitmap上的列表中的每一个项目。 你应该加载点播(LongListSelector.Realized方法),你必须摧毁它! 它会不会自动收集和GC.Collect的也不管用。 空引用是不是工作压力太大:(但这里是方法:请1x1像素的文件,将其复制到组装并从中资源流与1x1像素的空白处置你的形象自定义绑定处理方法LongListSelector.UnRealized事件(如。集装箱处理您的列表项)。

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宽度为我工作。

如果你错过了2步与数据收集可以看到好的结果,但之后100-200项目滚动内存溢出。



Answer 2:

你刚刚的Windows Phone与在屏幕上显示的所有图片的在用户的媒体库“图片”文件夹中。 这是令人难以置信的内存密集型,并考虑到150MB限制上WP8应用程式难怪你要OOM异常。

你应该考虑增加几件事情:

1)滚动ListBoxItem中拿出来看时,设置源和SourceUri属性为空。 请参阅“缓存图像”在Stefan的文章在这里@ http://blogs.msdn.com/b/swick/archive/2011/04/07/image-tips-for-windows-phone-7.aspx

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

2)如果你在WP8请务必设定DecodePixelWidth和/或DecodePixelHeight。 这样的图像将被加载到内存中,永久地调整,只有调整副本存储在内存中。 加载到内存中的图像可以更大然后是手机本身的屏幕尺寸。 所以那些裁剪到合适的尺寸和仅存储缩放后的图像是至关重要的。 设置BitmapImage.DecodePixelWidth = 480(最大),以帮助这一点。

var bmp = new BitmapImage();

// no matter the actual size, 
// this bitmap is decoded to 480 pixels width (aspect ratio preserved)
// and only takes up the memory needed for this size
bmp.DecodePixelWidth = 480;

bmp.UriSource = new Uri(@"Assets\Demo.png", UriKind.Relative);
ImageControl.Source = bmp;

(从代码示例这里 )

3)你为什么要使用Picture.GetImage()而不是Picture.GetThumbnail ()? 你真正需要的图像占用整个屏幕?

4)考虑从列表框移动到LongListSelector如果这是一个独特的WP8应用。 LLS具有好得多的虚拟化,然后列表框。 看你的代码示例它可能是足以让你只需要改变你的XAML列表框元素LongListSelector元素。



Answer 3:

试试这个办法: 图片下载,支持自动记忆清洗 。 在此示例项目: https://simca.codeplex.com/



文章来源: Why do I get an OutOfMemoryException when I have images in my ListBox?