9

我一直在开发 WP7 应用程序,它是图片库应用程序,实现了基本的缩放和轻弹手势。

出于测试目的,我使用设置为 Content 的离线图像(它们的文件名已编号)编译了该应用程序,并通过硬编码字符串(稍后将被替换)访问它们。

但后来意识到该应用程序消耗大量内存。我以为是图片的原因,发现了这个博客;图像总是被缓存。我使用博客中的代码来纠正这个问题。尽管消耗率确实下降了,但仍然没有释放内存。

对于最后的尝试,我创建了另一个带有基本功能 2 按钮的测试应用程序,用于导航和图像的图像控制,只是为了确保不是我的手势代码可能是问题。

这是xml

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Image Grid.Row="0" x:Name="ImageHolder" Height="Auto" Width="Auto" Stretch="Uniform" Tap="image_Tap" />
    <TextBlock x:Name="MemUsage" />
    <StackPanel Grid.Row="1" Orientation="Horizontal">
        <Button x:Name="PrevButton" Content="Prev" Width="240" Click="btnPrev_Click"/>
        <Button x:Name="NextButton" Content="Next" Width="240" Click="btnNext_Click"/>
    </StackPanel>
</Grid>

这是 .cs 文件

    const int PAGE_COUNT = 42;
    int pageNum = 0;
    public MainPage()
    {
        InitializeComponent();
        RefreshImage();
    }

    private void btnPrev_Click(object sender, RoutedEventArgs e)
    {
        pageNum = (PAGE_COUNT + pageNum - 1) % PAGE_COUNT; // cycle to prev image
        RefreshImage();
    }

    private void btnNext_Click(object sender, RoutedEventArgs e)
    {
        pageNum = (PAGE_COUNT + pageNum + 1) % PAGE_COUNT; // cycle to next image
        RefreshImage();
    }

    private void image_Tap(object sender, GestureEventArgs e)
    {
        RefreshTextData();
    }

    private void RefreshImage()
    {
        BitmapImage image = ImageHolder.Source as BitmapImage;
        ImageHolder.Source = null;
        if (image != null)
        {
            image.UriSource = null;
            image = null;
        }
        ImageHolder.Source = new BitmapImage(new Uri("000\\image" + (pageNum + 1).ToString("D3") + ".jpg", UriKind.Relative));
        RefreshTextData();
    }

    private void RefreshTextData()
    {
        MemUsage.Text = "Device Total Memory = " + (long)DeviceExtendedProperties.GetValue("DeviceTotalMemory") / (1024 * 1024)
            + "\nCurrent Memory Usage = " + (long)DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage") / (1024 * 1024)
            + "\nPeak Memory Usage = " + (long)DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage") / (1024 * 1024);
    }

但是仍然存在内存泄漏,我无法指出它。我很难找到它。内存分析器显示我有很多字符串实例,但我无法解释。

几点:

  • 我在文件夹“000”中有图像并命名为“image###”。目前我有文件名从“image001”到“image042”的图像
  • 测试应用程序的第一页完全显示图像后,内存占用为 6 MB,在第一页更改后,它上升到几乎 18-20 MB
  • 如果图像数量允许,随后的页面更改会导致内存逐渐增加,然后最终崩溃,否则在循环浏览所有图像后内存消耗是恒定的
  • 我正在使用尺寸约为 1280 x 2000 的 .jpg 文件进行测试,我没有调整图像大小。

堆摘要 -> 新分配

4

4 回答 4

6

我有相同类型的应用程序,带有下一张/上一张图片按钮。而且我有完全相同的内存泄漏,这让我发疯。

我仍然无法找到根本原因,但我已经设法用一个丑陋的黑客绕过它。在显示下一张图片时,我强制旧图像源加载无效图片,从而释放内存。我不明白为什么删除所有引用并调用垃圾收集器是不够的,必须在内部某个地方保存另一个引用。

无论如何,这里是黑客:

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

例如,您可以在您的RefreshImage方法中调用它:

private void RefreshImage()
{
    BitmapImage image = ImageHolder.Source as BitmapImage;
    ImageHolder.Source = null;

    DisposeImage(image);

    ImageHolder.Source = new BitmapImage(new Uri("000\\image" + (pageNum + 1).ToString("D3") + ".jpg", UriKind.Relative));
    RefreshTextData();
}

有点羞于使用它,但至少它似乎有效。

于 2012-11-20T21:36:54.037 回答
1

我已经尝试过您的代码示例,但在 Windows Phone 8 环境中,我无法重现泄漏。唯一的区别是我使用了自己的图像。

我的 512 WVGA 模拟器当前的内存使用量保持在 13MB,峰值保持在 14MB。我已经按了大约 20 次“下一个按钮”。

您是否也尝试过使用 Bindings for ImageHolder 而不是手动设置 Source?

(顺便说一句,从视觉上看,我在您的代码隐藏中看不到任何可能的内存泄漏)。

(另请查看这篇文章http://blogs.windows.com/windows_phone/b/wpdev/archive/2012/02/01/memory-profiling-for-application-performance.aspx

于 2012-11-16T08:18:08.857 回答
1

经过多次试运行和调试会话后,我发现当图像驻留在应用程序的独立存储中时,不会执行(或不积极执行)图像缓存。

问题是我正在使用作为 xap 文件一部分的图像,作为内容包含在内。我这样做是因为我只是想测试我的图像查看器。但是当我的应用程序完成时,情况就不是这样了。应用程序真正设计用于将图像存储在独立存储中并显示它们。

所以我设置了必要的代码,瞧,图像现在正在被垃圾收集,即使它们仍然被缓存。请参见下图(查看垃圾收集器被调用的次数)。这是一个不那么微不足道的问题的解决方案,这就是为什么没有其他人面临这种​​问题的原因。

我相信,当 WP7 silverlight 发现图像不是来自独立存储时,它会假定图像来自某个远程 URI,并决定无论如何都要缓存它。这就是silverlight图像缓存问题出现的地方。另一个答案证实这不会在WP8中发生。在此处输入图像描述

于 2012-11-21T06:02:13.610 回答
0

试试这个方法:带有自动内存清理的图像下载器。它是高级 KooKiZ 的示例,支持可视化。示例项目在这里:https ://simca.codeplex.com/

于 2013-10-02T19:39:53.030 回答