我有一个简单的应用程序,可以渲染图像并打印出来。为了方便设计,我使用了自定义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在保存到文件后收集这些图像。
大约需要2 GB的内存,最后抛出异常:
System.Drawing.dll中出现未处理的“System.OutOfMemoryException”类型异常
其他信息:内存不足。
如果我查看Visual Studio诊断工具,它看起来像:
让我们拍一张快照,看一下堆的内容,我们会看到有很多MemoryStream
s:
是什么导致MemoryStream
产生内存泄漏?据我所知,using()
会生成Dispose()
来电,应该对此进行处理。
P.S。如果我删除评论并调用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();
相同的结果。它也会占用更少的内存,但不能消除内存泄漏。