Windows Phone图像的高内存使用率

本文关键字:内存 使用率 高内存 Phone 图像 Windows | 更新日期: 2023-09-27 18:20:45

我正在Xamarin中使用MvvmCross开发Windows Phone应用程序。在这个应用程序中,用户从他的手机中选择一些图像。它们被显示在一个列表中,然后用户对它们进行处理。

我使用FileOpenPicker进行文件选择,并从这些文件中创建BitmapImages以显示

foreach (StorageFile file in args.Files) {
                    BitmapImage thumbnail = new BitmapImage();
                    thumbnail.DecodePixelType = DecodePixelType.Physical;
                    try {
                        using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read)) {
                            thumbnail.DecodePixelHeight = 70;
                            thumbnail.DecodePixelWidth = 70;
                            thumbnail.SetSource(fileStream);
                            fileStream.Dispose();
                        }
                    }
                    catch (OutOfMemoryException e) {
                        Mvx.Trace("MEMORY IS FULL");
                    }

在一些其他代码之后,我把这些BitmapImages放在ObservableCollection中,并像一样显示它们

<Image Style="{StaticResource imageListImage}" Source="{Binding Thumbnail}"/>

没什么特别的。我使用的测试图像的总大小为34MB。使用VS i的性能和诊断工具,我能够确定应用程序在启动时的内存使用量约为16Mb。当我将测试图像加载到应用程序中时,它的大小达到了58MB。就好像它仍然使用了图像的全尺寸一样。(只是为了测试)当我去掉decodepixel的高度和宽度时,它飙升到了大约350 MB。我完全不知道为什么它要用这么多内存来处理图像。

因为应用程序必须能够使用更多更大的图像,我需要找到一种方法来减少内存使用。有人知道我该怎么做吗?

Windows Phone图像的高内存使用率

压缩图片时,图片将使用34MB的存储空间。要显示,需要对它们进行解压缩。位图图片每像素使用4个字节(每个颜色通道RGB一个字节,alpha通道一个字节)因此,一张500万像素的图片将使用大约20 MB的RAM这就是为什么尽可能频繁地使用DecodePixelHeight/DecodePixelHeight至关重要。

尽管如此,有时,您必须操作巨大的图片(例如Lumia 1020的3800万张图片,每张图片有150 MB的RAM!!)。为此,诺基亚发布了Imaging SDK(现在由微软维护),允许您处理部分图片,而不必将全部内容加载到内存中。

在您的情况下,主要问题是您一次加载所有缩略图,即使只有少数缩略图会同时显示。如果你想减少使用的内存量,你必须延迟加载缩略图(也就是说,只有在需要的时候)。一种方法是存储文件位置而不是BitmapImage,并根据需要加载图片。不幸的是,您无法直接将路径绑定到Image控件(除非文件在应用程序的本地存储中)。在这个问题中,我建议为有类似问题的人使用自定义用户控件。

public sealed partial class LocalImage : UserControl
{
    public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof (string),
        typeof (LocalImage), new PropertyMetadata(null, SourceChanged));
    public LocalImage()
    {
        this.InitializeComponent();
    }
    public string Source
    {
        get { return this.GetValue(SourceProperty) as string; }
        set { this.SetValue(SourceProperty, value); }
    }
    private async static void SourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var control = (LocalImage)obj;
        var path = e.NewValue as string;
        if (string.IsNullOrEmpty(path))
        {
            control.Image.Source = null;
        }
        else
        {
            var file = await StorageFile.GetFileFromPathAsync(path);
            using (var fileStream = await file.OpenAsync(FileAccessMode.Read))
            {
                BitmapImage bitmapImage = new BitmapImage();
                await bitmapImage.SetSourceAsync(fileStream);
                control.Image.Source = bitmapImage;
            }
        }
    }
}