【问题标题】:How to assign screenshots to picturebox without using too much RAM如何在不使用太多 RAM 的情况下将屏幕截图分配给图片框
【发布时间】:2020-11-30 13:47:15
【问题描述】:

所以我有一个代码,我在其中创建位图和图形,并使用 CopyFromScreen 方法截取屏幕截图,然后我继续将其分配给图片框。它在一个线程内,所以它一直在运行。问题是 RAM 消耗不断增加,如果我尝试使用 graphics.Dispose() 和 bitmap.Dispose(),它会给出错误,因为在删除引用时,pictureBox 将没有任何东西可以显示。我已经尝试将位图克隆到另一个位图并处理原始位图,但结果相同,RAM 仍然上升。

这更像是一个问题,而不是一个有用的项目,但想法是图片框获得整个屏幕的实时副本。

我该如何解决这个问题?

代码示例:

while (run)
        {

            bitmap1 = new Bitmap(1920, 1080);
            g = Graphics.FromImage(bitmap1);

            g.CopyFromScreen(0, 0, 0, 0, size);

            form.setPictureBox1(bitmap1);
            
            
            g.Dispose();
            bitmap1.Dispose();
            GC.SuppressFinalize(this);
            

            Thread.Sleep(500);

        }

【问题讨论】:

  • 想一想:我给你 50 美元花。你到了商店,把它放在柜台上。在收银员拿走它之前,我抢走了它并点燃了它。你还能花那50美元吗?不,你在这里做同样的事情。将图像提供给图片框后,您将立即对其进行处理(请注意,将其分配给图片框时您并未制作副本 - 它是相同的图像)。处理旧图像不是更有意义吗?
  • 微软有完整的代码示例here

标签: c# .net bitmap


【解决方案1】:

所有原生对象都应该被释放。这包括图形和位图对象。您的代码失败,因为您在截屏后仍想使用位图。

如果您知道自己有固定大小,简单的方法是只创建一次位图,然后为每个屏幕截图重复使用它:

Bitmap myBitmap = new Bitmap(1920, 1080); // Make sure bitmap is disposed when the form is disposed.
public MyForm()
{
    myPictureBox.Image = myBitmap;
    ...
}
public void TakeScreenshot()
{
    using(var g = Graphics.FromImage(myBitmap))
    {
          g.CopyFromScreen(0, 0, 0, 0, myBitmap.Size);
    }
    myPictureBox.Invalidate();
 }

另一种选择是检查图片框是否已经有图像,并在替换之前将其处理掉。

【讨论】:

  • 我现在知道了,非常感谢!主要问题是我创建了很多位图,当我编写了在我脑海中有意义的代码时,哈哈。
【解决方案2】:

正如约翰建议的那样,您应该在创建新图像之前处理掉旧图像。您也可以处理图形。

下面是一个简单的例子,展示了可以做到这一点的一种方法:

private bool run = true;

private void Form1_Load(object sender, EventArgs e)
{
    Thread T = new Thread(new ThreadStart(Foo));
    T.IsBackground = true;
    T.Start();
}

private void Foo()
{
    Bitmap bmp;
    Size size = Screen.PrimaryScreen.Bounds.Size;
    while (run)
    {
        bmp = (Bitmap)pictureBox1.Image;
        pictureBox1.Image = null;
        if (bmp != null)
        {
            bmp.Dispose();
        }

        bmp = new Bitmap(1920, 1080);
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.CopyFromScreen(0, 0, 0, 0, size);
        }                 
        pictureBox1.Image = bmp;

        Thread.Sleep(500);
    }
}

【讨论】:

  • Foo()中的操作不会抱怨跨线程操作吗?相当确定你需要调用它。
  • @Nyerguds,试试看,告诉我你的结果。我相当肯定你会感到惊讶......
  • @Idle_Mind 这很难回答我的问题。仅仅因为单次测试运行没有出现错误就假设一切运行正常,这绝不是一个好主意。尝试处理该bmp,然后运行几分钟。它可能会继续工作。并不意味着没有任何问题。
猜你喜欢
  • 1970-01-01
  • 2019-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-04
  • 2011-10-21
相关资源
最近更新 更多