C# Dispose 函数报错

C# Dispose function giving an error

我正在尝试每 10 毫秒截取一次屏幕截图,并将它们设置为带有计时器的 Picturebox.image。几秒钟程序运行完美,但几秒钟后程序崩溃。我尝试在代码末尾使用 Dispose() 函数来清除内存,但 Dispose 函数也给出了错误。 (增加计时器的间隔无效)

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 gameBot
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public Bitmap screenshot;
        Graphics GFX;
        private void button1_Click(object sender, EventArgs e)
        {
            timer1.enabled = true;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            takescreenshot();
        }
        private void takescreenshot()
        {

            screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, 
            Screen.PrimaryScreen.Bounds.Height);
            GFX = Graphics.FromImage(screenshot);
            GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size);
            pictureBox1.Image = screenshot;
            screenshot.Dispose();              
        }           
    }
}

错误是

"An unhandled exception of type 'System.ArgumentException' occurred in System.Drawing.dll

附加信息:参数无效。

此外,程序在崩溃前使用了过多的 RAM(可能是因为内存不足异常而崩溃?) As you can see in here

我建议更改:

pictureBox1.Image = screenshot;
screenshot.Dispose();

至:

var oldScreenshot = pictureBox1.Image;
pictureBox1.Image = screenshot;
GFX.Dispose();
if (oldScreenshot != null)
    oldScreenshot.Dispose;

以确保在您分配新屏幕截图时处理旧屏幕截图。

Graphics.FromImage():

You should always call the Dispose method to release the Graphics and related resources created by the FromImage method.

此外,无需将图形保持在 Class 级别。

考虑到这一点,您只需要:

public Bitmap screenshot;

private void takescreenshot()
{
    if (screenshot != null)
    {
        screenshot.Dispose();
    }

    screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
    using (Graphics GFX = Graphics.FromImage(screenshot))
    {
        GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size);
    }
    pictureBox1.Image = screenshot;
}

1) 其实你的第一个问题 "Parameter is not valid." 是因为你正在处理截图对象。 如果您只尝试 运行 您的 takescreenshot() 方法一次 - 您将收到此错误。我假设发生这种情况是因为您将对象 "screenshot" 设置为 PictureBox1.Image 然后立即处理它。这是合乎逻辑的! PictureBox 无法呈现已处置的对象。

2) 尝试像这样修改按钮处理程序上的代码:

    private Object thisLock = new Object();
    private void button1_Click(object sender, EventArgs e)
    {
        Thread thr = new Thread(() =>
        {
            while (true)
            {pictureBox1.Invoke((Action)(() =>
                    {
                        screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                            Screen.PrimaryScreen.Bounds.Height);
                        GFX = Graphics.FromImage(screenshot);
                        GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0,
                            Screen.PrimaryScreen.Bounds.Size);
                        pictureBox1.Image = screenshot;
                    }));
                }
                Thread.Sleep(10);
        });
        thr.Start();
    }

工作正常!最好的方法是在picturebox完成渲染时获取事件,但我没有找到任何相关信息。