我在C#中创建了一个应用程序,它将连续执行屏幕捕获,并使用计时器在PictureBox中显示它。运行几秒钟后,出现了ArgumentException。
下面是代码和具有ArgumentException
的行private void timer1_Tick(object sender, EventArgs e)
{
Rectangle bounds = Screen.GetBounds(Point.Empty);
Graphics graphics;
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
using (graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(0, 0, 0, 0, new Size(bounds.Width , bounds.Height )); // ArgumentException
pictureBox1.Image = bitmap;
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
}
}
除此之外,我注意到在运行应用程序几秒钟后,Windows会发出低内存警报。
有关解决此问题的任何提示吗?
答案 0 :(得分:3)
您不断为图片框设置新的位图,并且永远不会丢弃先前的位图。一段时间后,系统缺少GDI句柄和/或内存(运行代码,我在15秒内消耗了一个内存)。
您可以简单地重复使用现有的位图:
Rectangle bounds = Screen.GetBounds(Point.Empty);
Image bitmap = pictureBox1.Image ?? new Bitmap(bounds.Width, bounds.Height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(0, 0, 0, 0, new Size(bounds.Width, bounds.Height));
if (pictureBox1.Image == null)
{
pictureBox1.Image = bitmap;
}
else
{
pictureBox1.Refresh();
}
}
您也不必在每次迭代时重置pictureBox1.SizeMode
。
或者,您可以手动配置以前的位图:
Rectangle bounds = Screen.GetBounds(Point.Empty);
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(0, 0, 0, 0, new Size(bounds.Width, bounds.Height));
using (Image prev_bitmap = pictureBox1.Image)
{
pictureBox1.Image = bitmap;
}
}
答案 1 :(得分:1)
pictureBox1.Image = bitmap;
是的,当您经常更新图片框时,您的程序将持续很长时间。 Bitmap类是单一的.NET类,其中IDisposable不容易被忽略。它就像一座冰山,位图可以使用大量的非托管内存但很少有内存。当您不再使用位图时,必须处理位图,以防止它们为其像素数据消耗所有可用的非托管内存。垃圾收集器往往会隐藏这个问题,但是当它没有经常运行时就不能这样做。而Bitmap的托管部分太小,无法经常触发收集。修正:
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
pictureBox1.Image = bitmap;
答案 2 :(得分:-1)
以下KB有助于理解此问题: Bitmap and Image constructor dependencies
GDI +,因此System.Drawing命名空间可能会推迟 解码原始图像比特直到图像需要比特。 另外,即使在图像被解码之后,GDI +也可以 确定丢弃大内存的效率更高 位图并稍后重新解码。因此,GDI +必须能够访问 位图或图像生命周期中图像的源位 宾语。
为了保持对源位的访问,GDI +锁定任何源文件,和 强制应用程序维护任何源流的生命周期 Bitmap或Image对象的生命周期。
必须弄清楚物体何时可以处置。