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;
以确保在您分配新屏幕截图时处理旧屏幕截图。
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完成渲染时获取事件,但我没有找到任何相关信息。
我正在尝试每 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;
以确保在您分配新屏幕截图时处理旧屏幕截图。
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完成渲染时获取事件,但我没有找到任何相关信息。