我正在构建一个小型 Windows Phone 8 应用程序(基督教东正教日历),它有一个应该更新动态磁贴的后台代理。该应用程序将需要访问手机中的联系人,因此我选择退出互联网访问,因此后端磁贴生成至少现在是没有问题的。我个人不会相信可以访问我的联系人和互联网的应用程序。
最近我的预定代理(生成三个 PNG)开始对我进行 OutOfMemoryException-ing。始终如一。我使用 DeviceStatus 来查询和调试它的行为。
很难将此称为内存泄漏,因为如果我调用 GC.Collect 在所有三个 tile 代之间它不会抛出 OutOfMemoryException。如果这是一个真正的内存泄漏,一些(大的和/或许多)对象将仍然被其他活动/根对象引用,并且没有任何 GC.Collect 会有所帮助。就我而言,GC.Collect会有所帮助。我可以继续使用 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 writer 取自ToolStack。
- 预生成图像是不可行的,因为有多个版本的“第一叠加”、“第二叠加”以及主要是“某些文本”。这至少意味着成千上万的图像。
问题的核心:我是否在做一些我不知道的非常错误的事情?我唯一想到的是 JPEG 的生成速度更快,内存消耗更少,但它们没有我想要的透明度。这实际上可以称为内存泄漏吗?
后期编辑:似乎经过更多调试后,它的行为从上面的行为改变为真正的内存泄漏。我从 PNG 生成切换到 JPEG 生成,现在内存较低。输入图像仍然是 PNG,但在另一端会吐出 JPEG。内存占用比之前的阈值低了几兆字节。
第二次编辑:我将逻辑放在按钮上的 10.000 重复循环中,似乎没有太多的内存消耗。我开始认为实际上并没有内存泄漏,而只是在生成过程中消耗了更高的内存,这足以让脆弱的代理崩溃。