Why is there a memory leak when I do not .Dispose() Bitmaps that I .Save() to a MemoryStream?

后端 未结 3 1740
灰色年华
灰色年华 2021-01-06 13:39

Say I create a Bitmap

Bitmap bitmap = new Bitmap(320, 200);

When I write it to some stream (in my case, it\'s a HttpResponseStream, as give

相关标签:
3条回答
  • 2021-01-06 14:07

    You must dispose the bitmap in order to release the GDI+ resources. It is that simple. It is one of the few times calling Dispose is required. If you are caching your bitmap to reduce disk access then clone the image and use the clone to save to the stream. I strongly recommend flushing, closing, and disposing of stream. When done, set clone and stream variables to null.

    0 讨论(0)
  • 2021-01-06 14:11

    Bitmap class utilizes unmanaged resources. These resources are not related to the resources utilized by the memory stream class. You can just wrap the bitmap class in a using statement to dispose of the bitmap instance when you are finished with it.

    Missed the latter part of your question. One way to "set it and forget it" is by creating a wrapper class that exposes the bitmap instance but implements a destructor that disposes of the bitmap instance. This destructor will mean the bitmap class is disposed of implicitly at garbage collection.

    As a final note: Any object you instantiate that implements IDisposable MUST be disposed of by your code. Dipose will never be implicitly called. Even in your first example. Just because you save the data to a stream does not meam that memory has then been deallocated. Most of the time it is a good idea to dipose of an object within the same segment of code that instantiated it. This assists in easier to read code by boosting code transparency.

    0 讨论(0)
  • 2021-01-06 14:21

    I think the issue is the assumption that the GC will magically clean up your objects. However, it may never do so, and here's what I think may be happening:

    Bitmaps use unmanaged resources to hold the bitmap data, and bitmap data is big. So you will be allocating a tiny block of managed memory and a huge block of unmanaged memory for each bitmap.

    So you leave your bitmap lying around for the GC to collect at its leisure. This works well for a lot of objects because soon there is enough memory pressure that the GC collects them to re-use the memory. BUt the GC looks at the managed heap and says "By disposing the uniused objects, I can only recover 64 bytes of memory. I won't bother". It doesn't see the gigabytes of unmanaged resources, just the few bytes on its heap.

    So you need to track and dispose of the bitmaps yourself.

    It is possible that sometimes you have seen it clean up for you. This will be because under sme circumstances (such as when you are disposing other objects like streams with larger memory footprints, or just because it's a tuesday afternoon) it does choose to process the unused blocks of memory, and then your bitmap is disposed at last. But you cannot rely on this happening.

    ...Ramble:

    There were two problems with pointers in the olden days.

    • They could be null, leading to crashing code
    • You could forget to free their memory/resources and get leaks

    So in .net they renamed "pointer" to "reference", added the GC and pretended that the problem didn't exist any more. Except that references can still be null, and programmers do still have to track and manage their resources to avoid leaks - just a little bit less often. I think this is a bad thing - it makes us lazy and inefficient without actually eliminating the underlying problem, so then it comes back and bites us, and we end up writing reams of Dispose logic where we used to just have a simple 'delete' in our destructors.

    0 讨论(0)
提交回复
热议问题