【问题标题】:C# Out of Memory when Creating Bitmap创建位图时 C# 内存不足
【发布时间】:2011-05-18 03:24:39
【问题描述】:

我正在创建一个应用程序(Windows 窗体),它允许用户根据他们选择的位置(拖动到选择区域)截取屏幕截图。我想添加一个放大的小“预览窗格”,以便用户可以更精确地选择他们想要的区域(更大的像素)。在 mousemove 事件中,我有以下代码...

private void falseDesktop_MouseMove(object sender, MouseEventArgs e)
    {
        zoomBox.Image = showZoomBox(e.Location);
        zoomBox.Invalidate();
        bmpCrop.Dispose();
    }

private Image showZoomBox(Point curLocation)
    {
        Point start = new Point(curLocation.X - 50, curLocation.Y - 50);
        Size size = new Size(100, 90);
        Rectangle rect = new Rectangle(start, size);
        Image selection = cropImage(falseDesktop.Image, rect);
        return selection;
    }

private static Bitmap bmpCrop;
private static Image cropImage(Image img, Rectangle cropArea)
    {
        if (cropArea.Width != 0 && cropArea.Height != 0)
        {
            Bitmap bmpImage = new Bitmap(img);
            bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
            bmpImage.Dispose();
            return (Image)(bmpCrop);
        }
        return null;
    }

失败并出现内存不足异常的行是:

bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);

基本上,它的作用是在鼠标指针周围取一个 100x90 的矩形并将其拉入 zoomBox,它是一个图片框控件。但是,在此过程中,我收到内存不足错误。我在这里做错了什么?

感谢您的帮助。

【问题讨论】:

  • 您的异常在哪一行被抛出?
  • 您是否曾经处理过 bmpCrop?
  • 为什么要在每次鼠标移动时创建一个新的裁剪图像,而不是重复使用现有图像?
  • @Steve,编辑:说明被抛出到 OP @CodeInChaos 的行,我确实在 zoomBox.Invalidate();对不起,我排除了它,将添加到操作中。
  • @CodeInChaos,因为我需要鼠标的更新图像/位置。

标签: c# winforms memory bitmap screenshot


【解决方案1】:

C# 成像中的内存不足,通常表示错误的矩形或点 - 有点红鲱鱼。我敢打赌start 在发生错误或Size.Hight + Y 或Size.Width + X 大于Hight 或图像宽度 时具有负X 或Y

【讨论】:

  • 看代码肯定是可能的。 start.x 是 curPos.X - 50(y 值相同)。那么当 curPos.x 或 curPos.y 小于 50 时会发生什么?
  • 我检查过了,我认为你可能是对的,我是从屏幕边缘尝试的....所以我所做的是从中间尝试,并且该错误又消失了上来了。参数无效。在我的 Program.cs -- 行 Application.Run(); (我没有实际使用的表单,它只是一个通知图标应用程序。
【解决方案2】:

MSDN 解释说 OutOfMemoryException 意味着

rect 超出源位图范围

其中rectBitmap.Clone 方法的第一个参数。

因此请检查cropArea 参数是否大于您的图像。

在 GDI+ 中,OutOfMemoryException 并不真正意味着“内存不足”; GDI+ 错误代码OufOfMemory 已被重载以表示不同的含义。其原因是历史性的,Hans Passant 在another answer 中对此进行了很好的描述。

【讨论】:

  • 在这种情况下,我希望 .net 在将代码传递到 GDI+ 之前检查传入的矩形,如果矩形无效则抛出适当的异常。
  • 在我的情况下,我的表单窗口很小,但图像的宽度 $ 高度比表单大。而from的BackgroundImageLayout模式是Tile。将 BackgroundImageLayout 设置为居中后,我的问题就消失了。
【解决方案3】:

像这样使用 Bitmap 对象:

using (Bitmap bmpImage = new Bitmap(img))
{
    // Do something with the Bitmap object
}

【讨论】:

    【解决方案4】:

    您应该检查 curLocation.X 是否大于 50,否则您的矩形将从负区域开始(当然还有 curLocation.Y)

    【讨论】:

    • 是的,我需要将其添加到我的代码中,但这仍然不是问题的原因。
    【解决方案5】:

    如果缩放框超出桌面区域的边缘,那么当您尝试裁剪时,您就是在要求系统制作包含视频内存区域之外像素的新图像。确保限制缩放框,使其范围不小于 0 或大于屏幕边缘。

    【讨论】:

      【解决方案6】:

      如果您一遍又一遍地创建新的位图,您可能需要调用 GC.Collect(); 这将强制 C# 进行垃圾收集

      【讨论】:

      • 我认为位图使用非托管内存,所以 Dispose 应该处理好内存。
      • 尝试在 zoomBox.Image = showZoomBox(e.Location) 之前调用 GC.Collect在鼠标移动甚至仍然失败。
      • 你应该 Dispose() 你不再需要的位图,而不是 GC.Collect!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-02
      • 1970-01-01
      • 2011-08-07
      • 1970-01-01
      • 1970-01-01
      • 2013-11-14
      • 2011-02-13
      相关资源
      最近更新 更多