WriteableBitmap或PNG编写器内存泄漏?

时间:2013-10-16 19:03:54

标签: windows-phone-8 windows-phone scheduled-tasks out-of-memory background-agents

我正在构建一个小型Windows Phone 8应用程序(基督教 - 东正教日历),它有一个后台代理,应该更新实时磁贴。该应用程序将需要访问手机中的联系人,所以我选择退出互联网访问,所以后端磁贴生成,至少现在是不可能的。我个人不相信有权访问我的联系人和互联网的应用程序。

最近,我的预定代理(生成三个PNG)在我身上启动了OutOfMemoryException。始终如一。我已经使用DeviceStatus来查询和调试它的行为。

如果我调用GC.Collect,它将不会抛出OutOfMemoryException,因此很难将此称为内存泄漏,因为在所有三个tile生成之间。如果它是真正的内存泄漏,一些(大的和/或许多)对象将继续被其他实时/根对象引用,并且没有任何数量的GC.Collect将有所帮助。在我的情况下GC.Collect WILL 帮助。我可以继续使用GC.Collect,但我感觉很脏。

在我开发应用程序免费和开源时,您可以在http://orthodoxcalendar.codeplex.com

详细查看当前开发状态​​下项目的所有代码

图块生成包括拍摄背景并在该背景上覆盖其他两个图像。基本上对于我生成的三个PNG中的每一个

var bytes1 = (byte[])resourceManager.GetObject(resourceName1);
var stream1 = new MemoryStream(bytes);

var bytes2 = (byte[])resourceManager.GetObject(resourceName2);
var stream2 = new MemoryStream(bytes);

var bytes3 = (byte[])resourceManager.GetObject(resourceName3);
var stream3 = new MemoryStream(bytes);

var writeableBitmap1 = BitmapFactory.New(size.Width, size.Height).FromStream(stream1); // background
var writeableBitmap2 = BitmapFactory.New(size.Width, size.Height).FromStream(stream2); // first overlay
var writeableBitmap3 = BitmapFactory.New(size.Width, size.Height).FromStream(stream3); // second overlay

writeableBitmap1.Blit(new Point(0, 0), writeableBitmap2, new Rect(0, 0, width2, height2), Colors.White, BlendMode.Alpha);
writeableBitmap1.Blit(new Point(0, 0), writeableBitmap3, new Rect(0, 0, width3, height3), Colors.White, BlendMode.Alpha);
writeableBitmap1.DrawText("Some text", new Point(5, 139), Color.Black, 17);
writeableBitmap1.Invalidate(); // flatten things

using(var outputStream = new WhateverStream())
{
  PNGWriter.Write(writeableBitmap1, outputStream);
}

writeableBitmap1.SetSource(new MemoryStream(MiscData.MinimumPng)); // set the writeable bitmap to a 1x1 transparent PNG to, hopefully, force it to release unamanaged memory or other stuff
writeableBitmap2.SetSource(new MemoryStream(MiscData.MinimumPng));
writeableBitmap3.SetSource(new MemoryStream(MiscData.MinimumPng));

stream1.Dispose();
stream2.Dispose();
stream3.Dispose();

代码,如果您将检查项目,并不完全像上面那样,因为我已经将几乎所有依赖项包装在适配器和提取的接口中。跨越许多集会。上面的代码是简化版本,它只显示了我认为的相关代码行。

上述代码的一些解释:

  • 所有这些代码都在Dispatcher.BeginInvoke中的后台代理中运行,因为您似乎无法在除UI线程之外的任何其他线程上操作WritableBitmap
  • PNG数据作为resx存储在另一个程序集中。我知道这会使程序集变胖,但是我需要这个以跨平台重用它,因为程序集是PCL
  • 使用字节数组直接创建WriteableBitmap似乎以一种神秘的方式失败,所以我将它包装在MemoryStream中,不知何故,这样,它可以工作
  • PNG作家来自ToolStack
  • 预生成图像是不可行的,因为存在多个版本的“第一叠加”,“第二叠加”,并且主要是“某些文本”。这至少意味着成千上万的图像。

问题的核心:我做了一些我不知道的非常错误的事情吗?我脑子里唯一想到的是JPEG生成速度更快,内存消耗更少但是他们不会有我想要的透明度。 这实际上可以称为内存泄漏吗?


LATER EDIT:似乎经过一些调试后,它将其行为从上面的行为改为真正的内存泄漏。我从PNG生成切换到JPEG生成,现在内存较低。输入图像仍然是PNG,但在另一端,JPEG将被吐出。内存占用量比之前的阈值低几兆字节。


第二次编辑:我将逻辑放在按钮上的10.000重复循环中,并且似乎没有太多的内存消耗。我开始认为没有真正的内存泄漏,但只有更高的内存消耗,这足以让脆弱的代理人失望。

1 个答案:

答案 0 :(得分:1)

在执行类似的操作时,我必须在调用GC.Collect之前将writeablebitmaps显式设置为null(即使应该是不必要的)。

此外,最好依次创建和销毁(并收集)每个图像,而不是全部创建它们然后将它们全部销毁。这将有助于任何一点的开销。

另请注意,在调试器中跟踪内存使用情况时,调试器会增加大约3mb的开销,而这些开销是您在实时时看不到的。