0

我有一个应用程序,我在其中获取位图并使用 GZipStream 压缩它并通过套接字发送它,所有这些都在内存中。我已经将肮脏的垃圾内存泄漏追踪到以下行:

frame.Save(inStream, jpegCodec, parameters);

浏览良好的信息高速公路,我发现了许多关于图像类在各种编解码器的保存方法中泄漏内存的主题。问题是我真的找不到任何修复程序。所以我的问题如下:

  1. 这是什么原因造成的
  2. 我怎样才能解决这个问题

这是泄漏所在的 FrameStream 类中的完整 Write() 方法。

/// <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);
                    }
                }
            }
        }
    }
4

5 回答 5

4

我建议在 CLR Profiler 下运行代码来定位泄漏源。如果它是任何类型的托管对象(甚至是非托管资源),只要该错误不是由于托管类型泄漏了非托管句柄,您就可以看到泄漏的位置。如果它在框架代码中,您可能可以使用反射和 P/Invoke 来解决它。

例如,该类型在某些情况下会Icon泄漏 Win32 。HICON解决方法是HICON通过 PInvokingDeleteObject函数使用Icon.

于 2009-05-16T05:28:05.257 回答
3

好的,在尝试了每个人的想法和想法以及许多其他方法之后。我终于尝试了简单的:

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

好吧,这行得通,内存泄漏已修复。我尝试强制调用垃圾收集器,手动处理位图,使用 P/Invoke DeleteObject,没有任何效果,但使用 using 语句可以。所以这让我想知道在我错过的 using 语句的底层会发生什么......

于 2009-05-16T06:22:55.733 回答
2

处理完毕后,您应该将位图设置为空。

此外,您可能希望在处理位图后调用垃圾收集器(即使这是一项昂贵的操作):GC.Collect();

位图拥有非托管资源 - GC 并不总是与这些“在球上”。这是一个关于 Bitmap 类的有趣链接(从紧凑框架的角度来看):http ://blog.opennetcf.com/ctacke/PermaLink,guid,987041fc-2e13-4bab-930a-f79021225b74.aspx

于 2009-05-16T05:25:09.227 回答
0

我对插座了解不多。但是,我知道阻止 Image 类内存泄漏的一种方法是冻结位图。希望这篇文章可以为您提供更多信息。MemoryStream.Dispose 会失败吗?从而造成内存泄漏。

于 2009-05-16T03:43:44.743 回答
0

您是否正在调用 Graphics 对象的 .Dispose() 方法?这导致内存泄漏。编辑:一旦你写了字节[],你现在就可以清楚地看到 Bitmap 对象的 .Dispose() 了。

于 2009-05-16T03:44:52.197 回答