通用GDI+错误:在调用GC.Collect()时避免

本文关键字:Collect GC 错误 GDI+ 调用 通用 | 更新日期: 2023-09-27 17:50:10

我有这段代码("ruta1"answers"ruta2"是包含不同图像路径的字符串):

   Bitmap pic;
   Bitmap b = new Bitmap(SomeWidth, SomeHeight);
   g = Graphics.FromImage(b);
   g.FillRectangle(new SolidBrush(Color.White), 0, 0, b.Width, b.Height);
   b.Save(ruta2, ImageFormat.Jpeg);
   g.Dispose();
   b.Dispose();
   b = new Bitmap(OtherWidth, OtherHeight);
   pic = new Bitmap(ruta2);
   g = Graphics.FromImage(b);
   g.FillRectangle(new SolidBrush(Color.White), 0, 0, b.Width, b.Height);
   g.DrawImage(pic, 0, 0, pic.Height, pic.Width); 
   pic.Dispose();
   b.Save(ruta2, ImageFormat.Jpeg);
   g.Dispose();
   b.Dispose();
   pic = new Bitmap(ruta1);
   b = new Bitmap(AnotherWidth, AnotherHeight);
   g = Graphics.FromImage(b);
   g.FillRectangle(new SolidBrush(Color.White), 0, 0, b.Width, b.Height);
   int k = 1;
   // I just draw the "pic" in a pattern on "b"
   for (h = 0; h <= b.Height; h += pic.Height)
       for (w = 0; w <= b.Width; w += pic.Width)
            g.DrawImage(pic, w, h, k * pic.Width, k * pic.Height);
   pic.Dispose();            
   GC.Collect();  // If I comment this line, I get a "generic GDI+ Error" Exception
   b.Save(ruta1, ImageFormat.Jpeg);
   g.Dispose();
   b.Dispose();

没关系,如果我设置pic = null后处置它,如果我不调用垃圾收集器,我得到了一个"通用GDI+错误"异常。只有当我调用垃圾回收器时,我的程序才会一直正常运行。

谁能解释一下这种行为?它是否依赖于。net框架版本?我使用的是Visual c# Express 2008,带有。net框架3.5

通用GDI+错误:在调用GC.Collect()时避免

首先,如果您使用" using "关键字来限定一次性对象(如BitmapGraphics)的使用范围,而不是对每个对象手动调用Dispose(),那就更好了。使用"using"有很多更好的原因,比如在抛出异常时清理东西,但它也极大地有助于代码的可读性。

第二,GDI笔刷也是IDisposable对象,所以你不应该创建并忘记它们。这样做:

using (var brush = new SolidBrush(Color.White))
{
    g.FillRectangle(brush, 0, 0, width, height)
}

…或者更好的是,在应用程序开始时创建画笔,并一直使用到最后(但也不要忘记处理它们)。IIRC,如果频繁创建/处理画笔,会对性能产生很大影响。

第三,我相信你的bug在第二部分:

  1. 打开图片"ruta2"
  2. 创建新图像
  3. 在新图像中绘制ruta2的内容
  4. 你把新东西保存在"ruta2"文件的顶部,但是从第一步开始的原始图像仍然被加载,并且可能对"ruta2"文件有一些处理,所以你需要在覆盖文件之前处理它。

如果你像这样重构第二部分,它应该可以工作:

using (var b = new Bitmap(OtherWidth, OtherHeight))
using (var g = Graphics.FromImage(b))
{
     using (var brush = new SolidBrush(Color.Red))
     {
         g.FillRectangle(brush, 0, 0, b.Width, b.Height);
     }
     using (var pic = new Bitmap(ruta2))
     {
         g.DrawImage(pic, 0, 0, pic.Height, pic.Width);
     }
     b.Save(ruta2, ImageFormat.Jpeg);
 }