可写位图或 PNG 写入器内存泄漏



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

最近,我的计划代理(生成三个PNG)对我启动了OutOfMemoryExceptioning。一贯。我使用设备状态来查询和调试其行为。

很难

称之为内存泄漏,因为如果我调用 GC,则在所有三代瓦片之间。收集它不会抛出 OutOfMemoryException。如果是真正的内存泄漏,则某些(大型和/或许多)对象仍将被其他活动/根对象引用,并且没有多少GC。收集会有所帮助。就我而言,GC。收集有所帮助。我可以继续使用 GC。收集,但我觉得这样做很脏。

当我开发免费和开源的应用程序时,您可以在当前开发状态下详细查看项目的所有代码 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
  • 直接使用字节数组创建可写位图似乎以一种神秘的方式失败,所以我把它包装在 MemoryStream 中,不知何故,这样,它可以工作
  • PNG 编写器取自 ToolStack。
  • 预生成图像是不可行的,因为有多个版本的"第一个叠加"、"第二个叠加",主要是"一些文本"。这至少意味着数以万计的图像。

问题的核心:我是否做了一些我不知道的严重错误?我脑海中唯一浮现的是 JPEG 的生成速度更快,内存消耗更少,但它们没有我想要的透明度。这真的可以称为内存泄漏吗?


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


第二次编辑:我将逻辑放在按钮上的 10.000 重复循环中,似乎没有太多的内存消耗。我开始认为并没有真正的内存泄漏,只是在生成过程中内存消耗更高,这足以使脆弱的代理下降。

在做类似的事情时,我必须在调用 GC 之前将可写位图显式设置为 null(即使应该是不必要的)。收集。

此外,最好

依次创建和销毁(和收集)每个图像,而不是创建所有图像然后销毁所有图像。这将有助于减少任何一个点的开销。

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

最新更新