4

I am saving a screenshot of current image on the computer:

Rectangle bounds = Screen.GetBounds(Point.Empty);

using (var bitmap = new Bitmap(bounds.Width, bounds.Height))
{
    using (Graphics g = Graphics.FromImage(bitmap))
    {
       g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
    }

    using (var mss = new MemoryStream())
    {
        bitmap.Save(mss,ImageFormat.Gif);
    }
}

And the memoryleak is at this code:

bitmap.Save(mss,ImageFormat.Gif);

Shouldn't my use of using dispose everything I am using?

Why am I still getting really high memory usage when taking lots of pictures and the memory ain't released back?

Thank you!

Gustavo Mori
  • 8,319
  • 3
  • 38
  • 52
syncis
  • 1,395
  • 4
  • 25
  • 43

2 Answers2

3

You may be seeing the same problem that I encountered when I asked this question on SO.

The problem in my case was that the MemoryStream was not releasing its internal byte[] even when calling Dispose on it. The byte[] is not freed until the MemoryStream goes out of scope and is collected by the GC.

This blog post details the cause of the problem, and also presents a working solution. It worked for me, and I suspect you are encountering the same problem. Essentially it wraps the underlying MemoryStream in a type that implements the same interface but sets the stream reference to null upon calling Dispose(). As no other objects should have a live reference to the internal stream this allows the GC to swoop in and clean it up.

Also, this issue is compounded by the fact that the internal byte[] will likely be allocated on the large object heap, which leads to fragmentation after multiple allocations.

Community
  • 1
  • 1
Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • I am reading it know, did u use the whole class in your situation? – syncis Jun 20 '11 at 20:58
  • Yep, I used the whole class. Not sure how you could get away with any less. It inherits from the abstract `Stream` class, so you have to implement all of those methods and that's what allows it to be treated as a Stream, even though all of the real work is passed down. – Ed S. Jun 20 '11 at 21:01
  • So i put current memorystream inside the new wrappedstream right? using (WrappingStream wp = new WrappingStream(mss)) Gonna try it – syncis Jun 20 '11 at 21:08
  • Yep, just like that. Also, I would suggest using a profiler if you're not already. The [Redgate ANTS .NET Memory Profiler](http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/) is awesome and they have a 14 day trial (I do not work for them, just like the product :) ) – Ed S. Jun 20 '11 at 21:14
  • Are you sure? At this point you need to run your app through a profiler and come back with the results. Until you do that we are just guessing. – Ed S. Jun 20 '11 at 21:20
2

You could try to use the BufferManager, it will manage Byte[] for you.

        // declare the BufferManager somewhere. Check thread safety!
        BufferManager bm = BufferManager.CreateBufferManager(qqq, yyy);


        // wrap your current code to use the buffer manager
        Rectangle bounds = Screen.GetBounds(Point.Empty);

        using (var bitmap = new Bitmap(bounds.Width, bounds.Height))
        {
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
            }

            byte[] buffer = bm.TakeBuffer(yyy);
            try
            {
              using (MemoryStream stream = new MemoryStream(buffer))
              {
                 bitmap.Save(mss,ImageFormat.Gif);
              }
            }
            finally
            {
               bm.ReturnBuffer(buffer);
            }
       }
flayn
  • 5,272
  • 4
  • 48
  • 69
  • Why not just new byte[]? Why BufferManager? It will 1) return buffers of lengths that are either 1M, 2M, 4M, 8M, 16M and so on (and I assume also buffers smaller than 1M, but didn't verify), so if you ask for 9M, you'll get a 16M array. 2) buffer managers will never clean up by themselves, so you have to manually call BufferManager.Clean(). See also http://stackoverflow.com/questions/7252417 and http://stackoverflow.com/questions/7265299 – Evgeniy Berezovsky Sep 02 '11 at 01:28