【问题标题】:C# bitmaps causes memory leakC# 位图导致内存泄漏
【发布时间】:2016-03-14 10:09:26
【问题描述】:

我有一个简单的应用程序,它可以渲染图像并将其打印出来。为了方便设计,我使用了自定义Control

现在,我有一个 1800 x 2400 大小的简单控件(是的,相当大):

public class PhotoControl : UserControl
{
    public PhotoControl()
    {
        InitializeComponent();
    }
}

还有一个扩展类,它使用它来生成图像:

public static class PhotoProcessor
{
    private static readonly PhotoControl PhotoForm = new PhotoControl(); // Single instance

    public static Image GenerateImage(this Photo photo)
    {
        PhotoForm.SetPhoto(photo); // Apply a photo

        Image result;
        
        using (Bitmap b = new Bitmap(PhotoForm.Width, PhotoForm.Height))
        {
            Rectangle r = new Rectangle(0, 0, b.Width, b.Height);
            PhotoForm.DrawToBitmap(b, r); // Draw control to bitmap

            using (MemoryStream ms = new MemoryStream())
            {
                b.Save(ms, ImageFormat.Png); // Save bitmap as PNG
                result = Image.FromStream(ms); 
            }
        }

        // GC.Collect();
        // GC.WaitForPendingFinalizers();

        return result; // return
    }

现在,我尝试使用它生成 30 张照片:

myPhoto.GenerateImage().Save(@"Output1.png", ImageFormat.Png);
myPhoto.GenerateImage().Save(@"Output2.png", ImageFormat.Png);

我不存储引用,我只是保存一个图像,并期望 GC 将这些图像保存到文件后收集。

大概会占用2GB内存,最后抛出异常:

System.Drawing.dll 中出现“System.OutOfMemoryException”类型的未处理异常

附加信息:内存不足。

如果我查看 Visual Studio 诊断工具,它看起来像:

我们来一张快照,看一下堆的内容,我们会看到有很多MemoryStreams:


是什么导致MemoryStream 产生内存泄漏?据我所知,using() 会生成 Dispose() 调用,它应该会处理它。

附:如果我删除评论并调用 GC.Collect(); GC.WaitForPendingFinalizers();,那么它会减少 2-3 倍的内存,但它仍然会增长 - 大约 200 张图像仍然会杀死一个应用程序。

将图像保存更改为以下内容:

Image img;

img = myPhoto.GenerateImage();
img.Save(@"Output1.png", ImageFormat.Png);
img.Dispose();

img = myPhoto.GenerateImage();
img.Save(@"Output2.png", ImageFormat.Png);
img.Dispose();

将产生与使用GC.Collect(); 相同的结果。它也会占用更少的内存,但不会消除内存泄漏。

【问题讨论】:

  • Image不需要处理吗?你要退回它并且永远不会丢弃
  • @Rob 我猜不存储对图像的引用会使 GC 收集它。无论如何,保存后使用Dispose 并不能解决问题。我已经更新了我的答案。谢谢。
  • 你确定这是产生问题的地方吗? MemoryStream 大小始终相同,但您使用不同的图像(例如 Output1.pngOutput2.png)。会不会是其他MemoryStream
  • @Sinatr 我在一个空白项目中重现了这个问题,除了这个 GenerateImage 调用之外什么都没有。我想,它总是有相同的大小,因为图像实际上是相同的 - 看,我总是从 myPhoto 生成图像 :)
  • @YeldarKurmangaliyev 您能否在某处托管整个解决方案(重现问题的小解决方案)?如果今晚我有时间,我可以仔细看看(以及其他人能够)

标签: c# image memory-leaks bitmap garbage-collection


【解决方案1】:

Image 实现了IDisposable,因此必须手动处理。您目前正在从 GenerateImage 返回一个 Image,但在保存后未将其丢弃。

【讨论】:

    猜你喜欢
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    • 2019-10-21
    • 2012-06-10
    • 2013-10-01
    • 1970-01-01
    相关资源
    最近更新 更多