The Using Pattern

When I teach and speak at conferences, one thing I stress a lot is releasing object resources as soon as possible! This allows the garbage collector to remove the object from the memory heap faster and lowers the memory footprint of the application. So, all objects that expose a finalizer should also have a method (from IDisposable) called Dispose. It’s our job as good programmers to call Dispose as soon as we are done with the object, not at the end of the method or sometimes never (as I see in code). One of the safe ways of doing this by calling Dispose in the Finally block of a Try/ Catch. But this itself could cause an exception if the object was never created properly. The safer way is to use the Using pattern.

I see code like this all the time:

Bitmap logoImage = new Bitmap(_logoPath);
MemoryStream ms = new MemoryStream();
logoImage.Save(ms, ImageFormat.Jpeg);
logoImage.Dispose();

The code could definitely cause an exception and then Dispose would never be called. This can actually cause “.NET memory leaks” which means virtual memory will not be released until the program closes or the computer runs out of it… I’ve seen this happen! This is especially important when dealing with images like in the code above.

The proper way to write the code above is like this:

using (Bitmap logoImage = new Bitmap(_logoPath))
{
  MemoryStream ms = new MemoryStream();
  logoImage.Save(ms, ImageFormat.Jpeg);
  ms.Close();
}

Actually, there is another problem with this code, MemoryStream is not being disposed of at all! The code should really be this:

using (var logoImage = new Bitmap(_logoPath))
{
  using (var ms = new MemoryStream())
  {
    logoImage.Save(ms, ImageFormat.Jpeg);
  }
}

Tip Submitted By: David McCarter

Advertisements

4 thoughts on “The Using Pattern

  1. I don’t want to detract from your excellent point. It is, indeed, an excellent point. I’m not kidding. And the particular example you chose is a good one: How To Properly Dispose() After Saving A Bitmap.

    But there’s a related task that’s prone to an error. Anyone who reads your example might then assume they need to properly Dispose() after loading a Bitmap. And per MSDN, that’s actually an error. I’m looking for the KB link now. If you load a Bitmap from a MemoryStream, you must not Dispose() that MemoryStream until you’re done with the Bitmap. And so in that one case, you need to be careful NOT to use the Using Pattern.

    1. So then how would the caller ever know that the bitmap was created using a MemoryStream and be able to dispose it off correctly? From the callers perspective, the only thing that he has is a bitmap, which he can dispose off correctly. hmm… maybe I am missing something.

      1. The Bitmap may be safely Disposed(); it’s the MemoryStream that you have to be careful with. This code will break (and since I’m typing on the fly without IntelliSense or compiler, it probably has syntax errors, too):

        public Bitmap GetBitmapFromBytes(byte[] bytes)
        {
        using(MemoryStream ms = new MemoryStream(bytes))
        {
        return new Bitmap(ms);
        }
        }

        Even though using is normally a Best Practice, here it’s a bug. You’ll get an exception when you try to do anything with that Bitmap. You have to rewrite this method as follows:

        public Bitmap GetBitmapFromBytes(byte[] bytes)
        {
        MemoryStream ms = new MemoryStream(bytes);
        return new Bitmap(ms);
        }

        Somewhere under the covers, that Bitmap keeps a reference to its stream. My guess — and it’s only a guess — is they do some sort of optimization, only loading the bytes from the stream the first time they’re actually needed.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s