WriteableBitmap或PNG编写器内存泄漏? [英] WriteableBitmap or PNG writer memory leak?

查看:98
本文介绍了WriteableBitmap或PNG编写器内存泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个小型Windows Phone 8应用程序(基督教东正教日历),该应用程序具有应更新实时磁贴的后台代理.该应用程序将需要访问手机中的联系人,因此我选择不使用Internet访问,因此至少现在不存在后端磁贴生成的问题.我个人不相信可以访问我的联系人和互联网的应用程序.

I am building a small Windows Phone 8 app (a Christian-Orthodox calendar) which has a background agent which should update the live tile. The app will require access to the contacts in the phone so I opted out of internet access so backend tile generation is, at least now out of question. I personally would not trust an app that has access to my contacts AND to internet.

最近,我的预定代理(生成三个PNG)对我启动了OutOfMemoryException-ing.始终如一.我已经使用DeviceStatus来查询和调试其行为.

Recently my scheduled agent (which generates three PNGs) started OutOfMemoryException-ing on me. Consistently. I've used DeviceStatus to query and debug its behavior.

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

It's hard to call this a memory leak since between all three tile generations if I call GC.Collect it won't throw OutOfMemoryException. If it were a true memory leak some (large and/or many) objects would remain referenced by other live/root objects and no amount of GC.Collect will help. In my case GC.Collect WILL help. I can continue using GC.Collect but I feel dirty doing so.

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

As I'm developing the app free and open-source you can view in detail all the code of the project at the current state of development at http://orthodoxcalendar.codeplex.com

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

The tile generation consists of taking a background and overlaying two other images on that background. Basically for each of the three PNGs generated I do

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();

如果您要检出项目,则代码与上面的代码并不完全相同,因为我几乎将所有依赖项都包装在适配器和提取的接口中.跨许多程序集.上面的代码是简化版本,仅显示了我认为是相关的代码行.

The code, if you'll check out the project, is not exactly like above since I've wrapped almost all dependencies in adapters and extracted interfaces. Across many assemblies. The above code is the simplified version which just shows, what I consider to be, the relevant code lines.

以上代码的一些解释:

  • 所有这些代码都在Dispatcher.BeginInvoke中的后台代理中运行,因为您似乎无法在UI线程以外的任何其他线程上操作WritableBitmap
  • PNG数据作为resx存储在另一个程序集中.我知道这可以增强程序集的功能,但是由于程序集是PCL,因此我需要它在各个平台之间重复使用
  • 直接使用字节数组创建WriteableBitmap似乎以一种神秘的方式失败了,因此我将其包装在MemoryStream中,并且以某种方式可以正常工作
  • PNG编写者来自 ToolStack .
  • 预先生成图像是不可行的,因为存在第一覆盖",第二覆盖"和主要是某些文本"的多个版本.这至少意味着成千上万张图像.
  • all this code is run in the background agent inside a Dispatcher.BeginInvoke since you can't seem to manipulate a WritableBitmap on any other thread than the UI thread
  • The PNG data is stored in another assembly as resx. I know this fattens the assembly but I need this to reuse it across platforms as the assembly is a PCL
  • Creating the WriteableBitmap directly using a byte array seems to fail in a mysterious way so I'm wrapping it in a MemoryStream and somehow, this way, it works
  • The PNG writer is taken from ToolStack.
  • It's not feasible to pre-generate the images since there are multiple versions of "first overlay", "second overlay" and, mostly the "Some text". It would mean tens of thousands of images, at least.

问题的核心:我在做我不知道的严重错误吗?我唯一想到的是JPEG的生成速度更快,内存消耗更少,但是他们不会有我想要的透明度. 这实际上可以称为内存泄漏吗?

The heart of the question : Am I doing something awfully wrong that I'm not aware of? The only thing that pops in my mind is that JPEGs are generated faster and with less memory consumption but they won't have transparency which I desire. Can this be actually called a memory leak?

最新似乎经过更多调试后,它的行为才从上面的行为变成了真正的内存泄漏.我从PNG生成切换到JPEG生成,现在的内存较低.输入的图像仍然是PNG,但在另一端会吐出JPEG.内存占用空间比以前的阈值低了几兆字节.

LATER EDIT : It seems that after some more debugging it changed its behavior from the one above to a true memory leak. I switched from PNG generation to JPEG generation and the memory is lower now. The input images are still PNG but at the other end a JPEG will be spit. The memory footprint went several megabytes below the previous threshold(s).

第二我将逻辑放在一个按钮的10.000重复循环中,似乎没有太多的内存消耗.我开始认为实际上并没有发生内存泄漏,而是在生成过程中消耗了更高的内存,这足以使脆弱的代理程序崩溃.

SECOND EDIT : I put the logic in a 10.000 repeat loop on a button and there doesn't seem too much memory consumption. I am beginning to think that there isn't really a memory leak but just higher memory consumption during the generation and that's enough to bring the fragile agent down.

推荐答案

在做类似的事情时,我不得不在调用GC.Collect之前显式地将writeablebitmaps设置为null(即使应该是不必要的).

In doing a similar thing I've had to explicitly set the writeablebitmaps to null (even though should be unnecessary) before calling GC.Collect.

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

Additionally, it may be better to create and destroy (and collect) each of the images in turn, rather than creating them all and then destroying them all. This will help with the overhead at any one point.

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

Also note that when tracking the memory use in the debugger, the debugger adds about 3mb of overhead that you won't see when live.

这篇关于WriteableBitmap或PNG编写器内存泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆