【问题标题】:C# Error: An unhandled exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dllC# 错误:System.Drawing.dll 中出现“System.OutOfMemoryException”类型的未处理异常
【发布时间】:2015-12-18 02:43:15
【问题描述】:

有一段时间,我在 C# 中使用 pictureBox 为模拟和其他事情做动画。现在我正在编写代码来攻击一个朋友(他只需要按 alt-f4 即可关闭它,没什么大不了的。)但我一直收到这个错误:

An unhandled exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll
Additional information: Out of memory.

代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EnrogSecurityBreach
{
    public partial class Form1 : Form
{
    Timer timer = new Timer();
    Form1 form1;
    //Bitmap bmp;
    public Form1()
    {
        InitializeComponent();
        form1 = this;
        form1.TransparencyKey = Color.White;
        FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Maximized;



        pictureBox1.Left = 0;
        pictureBox1.Top = 0;
        pictureBox1.Width = Screen.PrimaryScreen.Bounds.Width;
        pictureBox1.Height = Screen.PrimaryScreen.Bounds.Height;
        timer.Enabled = true;
        timer.Interval = 10;
        timer.Tick += timer_tick;

    }
    Random rand = new Random();
    int partsection = 0;
    int waitint = 0;
    int ran1 = 0;
    int ran2 = 0;
    int intensifies = 0;
    public void timer_tick(object e, EventArgs ea)
    {
        Bitmap bmp;
        bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);

        using (Graphics g = Graphics.FromImage(bmp))
        {
            if (partsection == -1)
            {

            }

            else if (partsection<300)
            {
                if (waitint == 0)
                {

                    ran1 = rand.Next(0, pictureBox1.Width);
                            ran2 = rand.Next(0, pictureBox1.Width);
                    waitint = 10;
                }
                else
                {
                    waitint--;
                }

                g.FillRectangle(new SolidBrush(Color.Green), (float)ran1, (float)0, 3, pictureBox1.Height);
                g.FillRectangle(new SolidBrush(Color.DarkGreen), (float)ran2, (float)0, 3, pictureBox1.Height);

                partsection++;
            }
            else if (partsection < 1000)
            {
                if (intensifies < 255)
                {
                    intensifies++;

                }
                else
                {

                }
                g.FillRectangle(new SolidBrush(Color.FromArgb(intensifies,Color.Black)), (float)0, (float)0, pictureBox1.Width, pictureBox1.Height);
            }

        }
        pictureBox1.Image = bmp;

    }
    private void Form1_Load(object sender, EventArgs e)
    {

    }
}
}

感谢您的帮助。

【问题讨论】:

  • 你在泄露SolidBrushes,这是肯定的。你需要处理掉它们。我不确定的是您是否还需要明确处理旧的pictureBox1.Image 图像。每秒 100 个滴答声也相当过分......
  • 我需要更改哪些代码?不好意思,我只用c#写了半年左右。
  • 您的 SolidBrush 应该在 using 语句中,如您的 Graphics 或在单独的行中声明,以便您可以在 em 上调用 Dispose。或者更好的是,在类级别声明它们并重复使用相同的画笔,而不是每次都创建一个新画笔。对于pictureBox,您可以查看this answer。您可以将Tick 更改为 33 大约 30FPS,这应该足够流畅并且对硬件的负担更少。虽然不确定图片框。
  • 好的,就像 SolidBrush sb1 = new SolidBrush(); //使用代码 sb1.Dispose();
  • 更改代码以使用 3840x2160 的固定屏幕分辨率,它确实为我抛出了 OutOfMemoryException 。所以显然它确实泄漏了,尽管是由于延迟触发的 GC(见下面的伊恩回答)。在pictureBox1.Image = bmp; 之前添加if (pictureBox1.Image != null) pictureBox1.Image.Dispose(); 可能会解决内存不足的问题...

标签: c#


【解决方案1】:

您的位图需要声明为表单的实例变量。

编辑

具体来说,取消注释类实例变量中的Bitmap 声明。接下来,添加以下代码:

    protected override void OnResize(EventArgs e)
    {
        pictureBox1.Left = 0;
        pictureBox1.Top = 0;
        pictureBox1.Width = Screen.PrimaryScreen.Bounds.Width;
        pictureBox1.Height = Screen.PrimaryScreen.Bounds.Height;
        bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        base.OnResize(e);
    }

为什么?因为当窗体调整大小或用户更改屏幕分辨率时,您需要调整图片框的大小。现在,Bitmap 只声明了一次。我运行了几分钟的代码,没有任何不良影响。

顺便说一句,pictureBox1 调整大小的代码已从构造函数中删除。

【讨论】:

  • 你能详细说明我需要做什么吗?
【解决方案2】:

发生这种情况是因为您使用的某些资源是非托管的,并且您没有将其置于 using 块或任何其他在使用后处置非托管资源的方式下。内存因此泄漏。

例如,这些行,

g.FillRectangle(new SolidBrush(Color.Green), (float)ran1, (float)0, 3, pictureBox1.Height);
g.FillRectangle(new SolidBrush(Color.DarkGreen), (float)ran2, (float)0, 3, pictureBox1.Height);

可以改成

using (SolidBrush greenBrush = new SolidBrush(Color.Green))
using (SolidBrush darkGreenBrush = new SolidBrush(Color.DarkGreen)) {
    g.FillRectangle(greenBrush , (float)ran1, (float)0, 3, pictureBox1.Height);
    g.FillRectangle(darkGreenBrush, (float)ran2, (float)0, 3, pictureBox1.Height);
}

同样,这一行

g.FillRectangle(new SolidBrush(Color.FromArgb(intensifies,Color.Black)), (float)0, (float)0, pictureBox1.Width, pictureBox1.Height);

到这里

using (SolidBrush blackBrush = new SolidBrush(Color.FromArgb(intensifies, Color.Black)))
    g.FillRectangle(blackBrush, (float)0, (float)0, pictureBox1.Width, pictureBox1.Height);

另一个建议是您应该检查System.Drawing 上的非托管资源。由于可能有更多您显示但未指出的非托管资源 - 或者 - 您没有提出问题,但实际上在代码的其他部分中。

Here 更多的是非托管资源:

这里是Bitmap可能导致泄漏的另一种解释(由于小型托管Bitmap类包装器,可能由于垃圾收集器延迟触发而导致内存不足),请参阅explanation作者:Hans Passant 先生

【讨论】:

    【解决方案3】:

    @IronGeek 找到了解决方案:

    更改代码以使用 3840x2160 的固定屏幕分辨率,但它确实会为我抛出 OutOfMemoryException。所以显然它确实泄漏了,尽管是由于延迟触发的 GC(见下面的 Ian 回答)。添加 if (pictureBox1.Image != null) pictureBox1.Image.Dispose();就在pictureBox1.Image = bmp之前;可能会解决内存不足的问题...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-07
      • 1970-01-01
      • 2017-12-09
      • 1970-01-01
      • 1970-01-01
      • 2017-06-30
      • 2014-11-10
      • 1970-01-01
      相关资源
      最近更新 更多