Question

I have an application where I am taking a bitmap and compressing it using a GZipStream and sending it over a socket, all in memory. I have tracked down the dirty scumbag memory leak to the following line:

frame.Save(inStream, jpegCodec, parameters);

Browsing around the good ol' information superhighway I have found numerous topics about the Image class leaking memory in the save method on various codecs. Problem is there aren't really any fixes out there that I could find. So my questions are as follows:

  1. What causes this
  2. How can I fix this

Here is my full Write() method in my FrameStream class where the leak is located.

/// <summary>
    /// Writes a frame to the stream
    /// </summary>
    /// <param name="frame">The frame to write</param>
    public void Write(Bitmap frame) {
        using (EncoderParameter qualityParameter = new EncoderParameter(Encoder.Quality, 50L)) {
            using (EncoderParameters parameters = new EncoderParameters(1)) {
                parameters.Param[0] = qualityParameter;

                ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
                ImageCodecInfo jpegCodec = null;

                foreach (ImageCodecInfo codec in codecs) {
                    if (codec.MimeType == "image/jpeg") {
                        jpegCodec = codec;
                        break;
                    }
                }

                using (MemoryStream inStream = new MemoryStream()) {
                    frame.Save(inStream, jpegCodec, parameters); // HUUUGE Memory Leak
                    Byte[] buffer = new Byte[inStream.Length];
                    inStream.Read(buffer, 0, buffer.Length);

                    using (MemoryStream outStream = new MemoryStream()) {
                        using (GZipStream gzipStream = new GZipStream(outStream, CompressionMode.Compress)) {
                            gzipStream.Write(buffer, 0, buffer.Length);
                        }

                        Byte[] frameData = outStream.ToArray();
                        Byte[] packet = new Byte[15 + frameData.Length];
                        Byte[] frameLength = BitConverter.GetBytes(frameData.Length);

                        Array.Copy(frameLength, 0, packet, 0, frameLength.Length);
                        Array.Copy(frameData, 0, packet, 15, frameData.Length);

                        m_Socket.Send(packet);
                    }
                }
            }
        }
    }
Was it helpful?

Solution

I suggest running your code under CLR Profiler to locate the source of the leak. If it's a managed object of any type (even an unmanaged resource), as long as the bug isn't due to a managed type leaking an unmanaged handle, you'll be able to see where the leak is. If it's in framework code, you can probably work around it using reflection and P/Invoke.

For example, the Icon type leaks Win32 HICONs in some circumstances. The workaround for this is to manually dispose the HICON by PInvoking the DeleteObject function, using the handle exposed by the Icon.

OTHER TIPS

Okay, after trying everyones ideas and thoughts and numerous other methods. I finally tried the simple:

using (frame) {
    frame.Save(outStream, jpegCodec, parameters);
}

And well, this worked and the memory leak is fixed.. I tried forcefully invoking the garbage collector, disposing the bitmap manually, using P/Invoke DeleteObject, nothing worked, but using a using statement did. So this makes me wonder what happens underthehood on a using statement that I'm missing out on....

You should set the bitmap to null when done working with it, after disposal.

Also, you may want to invoke the Garbage Collector after disposal of the Bitmap (even though it is an expensive operation): GC.Collect();

Bitmap holds unmanaged resources - the GC is not always "on the ball" with these. Here is an interesting link regarding the Bitmap class (from the perspective of the compact framework): http://blog.opennetcf.com/ctacke/PermaLink,guid,987041fc-2e13-4bab-930a-f79021225b74.aspx

I don't know much about sockets. However, I know one way to stop a memory leak with the Image class is to freeze the bitmap. Hopefully, this post might provide you with some more information. Could the MemoryStream.Dispose be failing? Thereby, creating a memory leak.

Are you calling the .Dispose() method of your Graphics object? That will cause a memory leak. EDIT: Once you have written the byte[], you are now clear to .Dispose() of the Bitmap object.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top