【发布时间】: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.png、Output2.png)。会不会是其他MemoryStream? -
@Sinatr 我在一个空白项目中重现了这个问题,除了这个
GenerateImage调用之外什么都没有。我想,它总是有相同的大小,因为图像实际上是相同的 - 看,我总是从myPhoto生成图像 :) -
@YeldarKurmangaliyev 您能否在某处托管整个解决方案(重现问题的小解决方案)?如果今晚我有时间,我可以仔细看看(以及其他人能够)
标签: c# image memory-leaks bitmap garbage-collection