c# - Windows Phone 8中BitmapImage/Image控件的内存消耗

标签 c# windows-phone-8 out-of-memory bitmapimage

我正在测试一个 WP8 应用程序,它的图像查看器可以显示很多图像,我发现应用程序的内存消耗在增加,想知道如何解决它。

我从网上阅读了一些文章,但是这些文章提供的解决方案不适用于我的应用程序,请阅读下面的历史记录。

首先,我找到了文章“Image Tips for Windows Phone 7”并下载了它的示例以进行干净的图像缓存测试,它使用1 张图像

然后出于测试目的,我在应用程序内部使用15 个离线图像 编译了这个应用程序,并设置为“内容”,请从here 下载测试应用程序。 .

我的测试步骤是:

(1) Launch app
(2) Go to Image Caching page
(3) Enable checkbox "Avoid Image Caching"
(4) Continuously tapping button Show/Clear
(5) Keep watching the memory status textblock at the bottom

当我测试我的应用时,内存在增加,比如 16.02MB => Show(19.32MB) => Clear(16.15MB) => Show (20.18MB) => 清除 (17.03MB)...等等 即使离开缓存页面并再次转到缓存页面,内存也不会被释放。 文章“Image Tips for Windows Phone 7”的解决方案似乎仅适用于1 张图片

这里是“Image Tips for Windows Phone 7”解决方案的xaml和代码隐藏。

[缓存.xaml]

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
                <ToggleButton Content="Show" Width="150" Checked="ShowImageClicked" Unchecked="ClearImageClicked"/>
                <CheckBox x:Name="cbAvoidCache" Content="Avoid Image Caching"/>
            </StackPanel>
            <Image x:Name="img" Grid.Row="2" Width="256" Height="192"/>
            <TextBlock x:Name="tbMemory" Grid.Row="2" Text="Memory: " VerticalAlignment="Bottom" Style="{StaticResource PhoneTextLargeStyle}"/>
        </Grid>

[缓存.xaml.cs]

public partial class Caching : PhoneApplicationPage
{
    public Caching()
    {
        InitializeComponent();

        DispatcherTimer timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromMilliseconds(500);
        timer.Start();
        timer.Tick += delegate
        {
            GC.Collect();
            tbMemory.Text = string.Format("Memory: {0} bytes", DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage"));
        };
    }

    private int nIndex = 1;
    BitmapImage bitmapImageFromUri = new BitmapImage();
    private void ShowImageClicked(object sender, RoutedEventArgs e)
    {
        string strImage = string.Format("../ImagesAsContent/{0:D2}.jpg", nIndex);
        bitmapImageFromUri.UriSource = new Uri(strImage, UriKind.Relative);
        img.Source = bitmapImageFromUri;

        nIndex++;
        if (nIndex > 15)
        {
            nIndex = 1;
        }

        (sender as ToggleButton).Content = "Clear";
    }

    private void ClearImageClicked(object sender, RoutedEventArgs e)
    {
        if (cbAvoidCache.IsChecked == true)
        {
            // set the UriSource to null in order to delete the image cache
            BitmapImage bitmapImageFromUri = img.Source as BitmapImage;
            bitmapImageFromUri.UriSource = null;
        }
        img.Source = null;
        (sender as ToggleButton).Content = "Show";
    }
}

我也尝试搜索其他解决方案,一些测试结果如下。

(1)文章“[wpdev] Memory leak with BitmapImage”:它提供了两种解决方案,一种是DisposeImage API,另一种是将BitmapImage source设置为null,如下所示。这篇文章还让我们知道我们必须小心事件处理程序附加/分离,但是我的测试应用程序在缓存页面中没有事件处理程序。

[DisposeImage]

private void DisposeImage(BitmapImage image)
{
    if (image != null)
    {
        try
        {
            using (var ms = new MemoryStream(new byte[] { 0x0 }))
            {
                image.SetSource(ms);
            }
        }
        catch (Exception)
        {
        }
    }
}

[设置为空]

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

(2)文章“Windows phone: listbox with images out-of-memory”:它提供了一个API“DisposeImage”,与下面的(1)几乎没有区别,但这也不起作用,我仍然有内存增加的症状。

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
    {}
}

(3) 文章“Cannot find the memory leak”:它提供了与上述相同的 2 个解决方案,还提到了无法为独立存储的图像重现的问题,但是我的测试应用程序的图像来自独立存储。

(4) 我也尝试了1000张图片,测试结果是应用程序连续显示大约190张图片时应用程序崩溃,请引用下面的Windows Phone应用程序分析图内存。 enter image description here

最后,感谢您耐心阅读我的问题和历史记录,我已经为此努力寻找解决方案很多天了。 如果您有任何线索或解决方案,请告诉我。

谢谢。

最佳答案

我正在处理同样的问题,我想,最后,实际上我找到了一个解决方法,我不是专业程序员,但这是我的解决方案:

  public Task ReleaseSingleImageMemoryTask(MyImage myImage, object control)
    {
        Pivot myPivot = control as Pivot;
        Task t = Task.Factory.StartNew(() =>
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                if (myImage.img.UriSource != null)
                {
                    myImage.img.UriSource = null;
                    DisposeImage(myImage.img);
                }
                PivotItem it = (PivotItem)(myPivot.ItemContainerGenerator.ContainerFromIndex(myImage.number % 10));
                Image img = FindFirstElementInVisualTree<Image>(it);
                if (img != null)
                {
                    img.Source = null;
                    GC.Collect();
                }
            });
            myImage.released = true;
        });
        return t;
    } 


private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
    {
        var count = VisualTreeHelper.GetChildrenCount(parentElement);
        if (count == 0)
            return null;

        for (int i = 0; i < count; i++)
        {
            var child = VisualTreeHelper.GetChild(parentElement, i);

            if (child != null && child is T)
            {
                return (T)child;
            }
            else
            {
                var result = FindFirstElementInVisualTree<T>(child);
                if (result != null)
                    return result;
            }
        }
        return null;
    }

    private void DisposeImage(BitmapImage img)
    {
        if (img != null)
        {
            try
            {
                using (var ms = new MemoryStream(new byte[] { 0x0 }))
                {
                    img = new BitmapImage();
                    img.SetSource(ms);
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("ImageDispose FAILED " + e.Message);
            }
        }
    }

希望这有帮助:)

关于c# - Windows Phone 8中BitmapImage/Image控件的内存消耗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18127027/

相关文章:

c# - 如何确保文件从我的工作目录复制到 bin/Debug rsp。垃圾桶/释放?

c# - LINQ to SQL group by 显示不同外键的错误计数

audio - 将WP8应用最小化后,背景音频将停止,然后恢复

c# - 从 OutOfMemoryException 中恢复

c# - 如何使用/理解 lambda 表达式?

c# - Holotoolkit 中的 HandDraggable 和 GestureAction 脚本有什么区别?

javascript生成方波声音

c# - 如何在 Xaml 中调整带有折叠控件的 UI?

node.js - nodejs http response.write : is it possible out-of-memory?

Java - 数百万条记录,HashMap 抛出 OutOfMemoryError