首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >WriteableBitmap内存泄漏?

WriteableBitmap内存泄漏?
EN

Stack Overflow用户
提问于 2013-02-05 23:20:01
回答 5查看 6.3K关注 0票数 20

我正在使用下面的代码来创建一个基于UI元素的活动磁贴。它在WriteableBitmap上渲染uiElement,保存位图并返回文件名。这个方法是在windows phone后台任务代理中运行的,我遇到了内存限制。

代码语言:javascript
复制
private string CreateLiveTileImage(Canvas uiElement, int width, int heigth)
{
   var wbmp = new WriteableBitmap(width, heigth);
   try
   {
      wbmp.Render(uiElement, null);
      wbmp.Invalidate();

      var tileImageName = _liveTileStoreLocation;
      using (var stream = new IsolatedStorageFileStream(tileImageName, FileMode.Create, FileAccess.Write, IsolatedStorageFile.GetUserStoreForApplication()))
      {
         wbmp.SaveJpeg(stream, width, heigth, 0, 100);
         stream.Close();
      }

      uiElement = null;
      wbmp = null;
      GC.Collect();
      return "isostore:" + tileImageName;
   }
   catch (Exception exception)
   {
      // ...
   }
   return null;
}

我做了一些测试,问题是:这个方法会泄漏内存,但我不知道为什么/在哪里?!

在第一次使用这个方法之前,我还做了一些测试运行:

代码语言:javascript
复制
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
7.249.920 Bytes

这是正常的,因为调试器是附加的,它使用大约2MB内存。

再次运行此方法(重新设置为在调试器中再次运行方法):

代码语言:javascript
复制
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
8851456  long +  40960
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
8892416  long + 245760
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9138176  long + 143360
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9281536  long + 151552
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9433088  long + 143360
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9576448  long + 139264
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9715712  long + 139264
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9859072  long + 143360
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
10006528 long + 147456

因此,这种方法使用的内存增加了。

但是为什么呢?在我看来,没有阻止对象被收集的引用。

2013年4月5日上的更新

嗨,

谢谢你所有的回答!正如我所建议的那样,我减少了代码+最终能够在几行代码中重现问题。

代码语言:javascript
复制
void Main()
{
   for (int i = 0; i < 100; i++)
   {
      CreateImage();
   }
}

private void CreateImage()
{
   var rectangle = CreateRectangle();
   var writeableBitmap = new WriteableBitmap(rectangle, rectangle.RenderTransform);

   rectangle = null;
   writeableBitmap = null;
   GC.Collect();
}

private Rectangle CreateRectangle()
{
   var solidColorBrush = new SolidColorBrush(Colors.Blue);
   var rectangle = new Rectangle
   {
   Width = 1000,
   Height = 1000,
   Fill = solidColorBrush  // !!! THIS causes that the image writeableBitmap never gets garbage collected
   };

   return rectangle;
}

启动应用后: ApplicationCurrentMemoryUsage:“11+681+792字节”

1次迭代- ApplicationCurrentMemoryUsage:“28,090-368字节”

5次迭代- ApplicationCurrentMemoryUsage:“77-111-296字节”

20次迭代- ApplicationCurrentMemoryUsage:“260-378-624字节”

23次迭代后出现:内存不足异常。 Ln.:var writeableBitmap =新矩形(WriteableBitmap,rectangle.RenderTransform);

只需注释掉"Fill = solidColorBrush“这一行,CreateImage()方法就被调用了100次,没有任何问题--在第100次迭代之后,内存使用量大约是”16,064,512字节“。

所以看起来问题出在画笔!!当用来填充UI元素,然后这个UI元素被渲染到可写的位图上时,位图永远不会被垃圾回收。

当然,在我看来,这没有任何意义。画笔超出了作用域,所以它也应该被垃圾回收!(使用笔刷后将其设置为空不会更改任何内容)

我的许多UI元素都使用画笔进行填充,所以我不能简单地删除画笔的用法。你对这个问题怎么看?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-05-30 21:53:11

问题是rectangle.RenderTransform是一个对象的实例,如果您将writableBitmap设置为null,则rectangle.RenderTransform对象仍然是活动的,并在内存中保存矩形...因此,解决方案是编辑代码,如下所示:

代码语言:javascript
复制
private void CreateImage()
{
   var rectangle = CreateRectangle();
   var writeableBitmap = new WriteableBitmap(rectangle, rectangle.RenderTransform);

   rectangle.RenderTransform = null; //and your memory would be happy ;)
   rectangle = null;
   writeableBitmap = null;
   GC.Collect();
}

请看记忆截图...

之前:

之后:

票数 10
EN

Stack Overflow用户

发布于 2013-02-21 04:45:00

您在try catch中的最后一个参数应该是wbmp = null。

并且您正在渲染它,这意味着您正在将该对象附加到外部(函数)列表。因此,任何数量的GC.Collect都不会真正收集它,因为它仍在“运行”。

将uielement source设置为null,这可能会消除GC忽略它的原因所附加的引用。

票数 0
EN

Stack Overflow用户

发布于 2013-02-21 18:59:45

您可以限制可写位图图像的大小宽度X高度为较小的大小,当您增加它的大小时,它需要更多的内存,所以您可以先限制其初始大小,然后使用原始切片大小保存为jpeg

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14710838

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档