7

Our software renders technical drawings. One particular drawing made the application crash every time with an OutOfMemoryException. Upon investigation, nothing seemed out of the ordinary; the app didn't request a lot of memory, didn't use a lot of handles. I tried catching the exception and the app finished the drawing without throwing another one. In fact, there was always only the one OutOfMemoryException, and it was always the same graphics primitive that caused it.

The following code is the minimum required to cause this particular crash. It seems that the exact combination of image size, pen style and coordinates causes the exception. Rounding the coordinates down to three decimals makes it disappear, as does making the graphics dimensions smaller or using a pen without dashing.

using (Bitmap b = new Bitmap(200, 200))
{
  using (Graphics g = Graphics.FromImage(b))
  {
    using (Pen p = new Pen(Color.Black))
    {
      p.DashPattern = new float[]{10.0f, 2.0f};

      RectangleF r = new RectangleF(
        BitConverter.ToSingle(new byte[]{0xD3, 0x56, 0xB3, 0x42}, 0),
        BitConverter.ToSingle(new byte[]{0x87, 0x2D, 0x17, 0x43}, 0),
        BitConverter.ToSingle(new byte[]{0xE2, 0x81, 0xD1, 0x3F}, 0),
        BitConverter.ToSingle(new byte[]{0xE2, 0x81, 0xD1, 0x3F}, 0));
      float st = BitConverter.ToSingle(new byte[]{0x6B, 0xF6, 0x1A, 0x42}, 0);
      float sw = BitConverter.ToSingle(new byte[]{0x6D, 0x33, 0x4F, 0x40}, 0);

      g.DrawArc(p, r, st, sw);
    }
  }
}

In this case it's not complicated to create a workaround, but I was wondering if someone had an explanation for this.

4

1 回答 1

6

System.Drawing 是 GDI+ 的包装器,GDI+ 是一个比 .NET 发布早很多年的非托管库。它有一个典型的 C api 问题,错误报告相当差。GDI+ 只有 20 个不同的错误代码,对于这么大的代码块来说并不多。它们也是非常不透明的,特别是 Status::GenericError。一个非常常见的错误,对于许多没有共同点的可能错误条件返回。

System.Drawing 几乎无法使这些错误代码更具描述性,因为它们在设计上不是描述性的。Status::OutOfMemory 也符合这种模式。它几乎无能为力,但会生成一个托管异常,这意味着同样的事情。遗憾的是,这也不是一个好的选择,因为 OutOfMemoryException 在 .NET 中非常具体。

这里有很多损失,几乎没有获胜的方法。您只需要从表面上看待 GDI+ 糟糕的错误报告并解决问题。在这种情况下,避免将虚线笔用于非常小的弧线很可能会解决您的问题。无论如何,您都看不到破折号图案。

于 2013-02-18T15:19:12.183 回答