« Managed Debugging Assistant Configuration Files | Main | Finalizers called from partially constructed objects »

April 5, 2008

“Memory leak” with BitmapImage and MemoryStream

The code snippet below has a small “memory leak”:

BitmapImage bitmap = new BitmapImage();

 

byte[] buffer = GetHugeByteArray(); // from some external source

using (MemoryStream stream = new MemoryStream(buffer, false))

{

    bitmap.BeginInit();

    bitmap.CacheOption = BitmapCacheOption.OnLoad;

    bitmap.StreamSource = stream;

    bitmap.EndInit();

    bitmap.Freeze();

}

 

// use bitmap...

The BitmapImage keeps a reference to the source stream (presumably so that you can read the StreamSource property at any time), so it keeps the MemoryStream object alive. Unfortunately, even though MemoryStream.Dispose has been invoked, it doesn't release the byte array that the memory stream wraps. So, in this case, bitmap is referencing stream, which is referencing buffer, which may be taking up a lot of space on the large object heap. Note that there isn't a true memory leak; when there are no more references to bitmap, all these objects will (eventually) be garbage collected. But since bitmap has already made its own private copy of the image (for rendering), it seems rather wasteful to have the now-unnecessary original copy of the bitmap still in memory.

The solution here is fairly straightforward: create an implementation of Stream that wraps another stream (in this example, the MemoryStream). The Dispose method of this wrapper class needs to release the wrapped stream, so that it can be garbage collected. Once the BitmapImage is initialised with this wrapper stream, the wrapper stream can be disposed, releasing the underlying stream, and allowing the large byte array itself to be freed.

Posted by Bradley Grainger at April 5, 2008 12:40 PM

Trackback Pings

TrackBack URL for this entry:
http://ancientblogs.logos.com/mt-cgi/mt-tb.cgi/205