WriteableBitmap Memory Leak?

青春壹個敷衍的年華 提交于 2019-12-18 12:12:52

问题


i am using the code below to create a live tile, based on an UI element. It renders the uiElement on a WriteableBitmap, saves the bitmap + returns the filename. This method is run in a windows phone background task agent an i am running into memory limits.

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;
}

I did some testing and the problem is: This methods leaks memory, but i do not know why/where?!

I also did some test runs - before first run into this method:

Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
7.249.920 Bytes

This is ok, since the debugger is attached, which uses about 2 MB memory.

Doing some more runs of this method (set back to run method again in debugger):

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

So the memory, used by this method increases.

But why? In my opinion there are no references that prevent the objects from getting collected.

UPDATE on 04.05.2013

Hi,

thank you for all your answers! As suggested, i reduced the code + finnally was able to reproduce the problem in a few lines of code.

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;
}

After starting the App: ApplicationCurrentMemoryUsage: "11 681 792 Bytes"

1 Iteration - ApplicationCurrentMemoryUsage: "28 090 368 Bytes"

5 Iterations - ApplicationCurrentMemoryUsage: "77 111 296 Bytes"

20 Iterations - ApplicationCurrentMemoryUsage: "260 378 624 Bytes"

After 23 Iterations: Out of Memory Exception. Ln.: var writeableBitmap = new WriteableBitmap(rectangle, rectangle.RenderTransform);

Only by commenting out the line "Fill = solidColorBrush", the CreateImage() method was called 100 times without any problems - after the 100th iteration, memory usage was about "16 064 512 Bytes".

So it seems the problem is the brush!! When used to fill an UI element, and later this UI elemnt is renderes on a writeable bitmap, the bitmap never gets garbage collected.

Of course this makes no sense in my opinion. The brush runns out of scope so it simply should be garbage collected too! (Setting the brush to null after it was used did not change anything)

Many of my UI elements use a brush for filling, so i cannot simply remove the usage of brushes. What do you think about this issue?


回答1:


The Problem is that rectangle.RenderTransform is an instance of an object and if you set writableBitmap to null the rectangle.RenderTransform Object is still alive and holds the rectangle in the memory... so the solution is to edit the code as follows:

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

see the memory screenshots...

before:

after:




回答2:


Your finally in the try catch should be wbmp = null for a kick off.

And you are rendering it, which means you are attaching that object to an outside (the function) list. Therefore no amount of GC.Collect will actually collect it as it's still 'in play'.

Set the uielement source to null, that may get rid of the attached reference why the GC is ignoring it.




回答3:


You can limit the size of writable bitmap image width X height to smaller size as you when increase its size it takes more memory so you can limit its initial size at first then save as jpeg with original tile size




回答4:


i get same exception when convert uielement to writeablebitmap in taskagent. just tried so many times.i found a soluction get be worked.

wbmp.SaveJpeg(stream, width, heigth, 0, 60);

you can change the quality to 60 when you save uielement to stream. it well reduce memory useage. you can try it.




回答5:


Try to put this part:

      uiElement = null;
      wbmp = null;
      GC.Collect();

to finally clause;



来源:https://stackoverflow.com/questions/14710838/writeablebitmap-memory-leak

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!