Search code examples
c#memorybitmapmemorystream

MemoryStream uses too much memory and doesn't dispose/close


The memory usage goes up until it hits System.OutOfMemory exception. The MemoryStream instances count goes up until exception as well. I tried using using(), doing ms.Dispose(), ms.Close(), few other as well, GC.Collect(), etc. Is this maybe a memory leak?

  while(running){ 
var screen = Screen.PrimaryScreen;
                using(Bitmap bitmap = new Bitmap(screen.Bounds.Width, screen.Bounds.Height)) {
                    using(var g = Graphics.FromImage(bitmap)) {
                        g.CopyFromScreen(screen.Bounds.Left, screen.Bounds.Top, 0, 0, screen.Bounds.Size);
                    }
                    using(EncoderParameters encoderParams = new EncoderParameters(1)) {
                        encoderParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, ssQuality);
                        ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
                        ImageCodecInfo jgpEncoder = codecs[1];
                        using(var ms = new MemoryStream()) {
                            bitmap.Save(ms, jgpEncoder, encoderParams);
                            image img2 = new image();
                            img2.Img = Image.FromStream(ms);
                            binF.Serialize(client.GetStream(), img2);
                        }
                    }
                }
}

VS Memory View:

Memory View VS

Task Manager memory usage of the process:

Task Manager memory usage of the process


Solution

  • You need to dispose of image returned from Image.FromStream(ms);, e.g. like so:

    ms.Position = 0; // Rewind the stream.
    using (var image2 = Image.FromStream(ms)) 
    { 
        image img2 = new image { Img = image2 };
        binF.Serialize(client.GetStream(), img2);
    }
    

    This will ensure that, not only are the resources of the second image promptly disposed of, but also the MemoryStream ms is more likely to be promptly garbage-collected. It is not happening currently because Image keeps a reference to the stream from which it was created. This is alluded to in the docs which state:

    You must keep the stream open for the lifetime of the Image.