Как назначить скриншоты в picturebox, не используя слишком много оперативной памяти

#c# #.net #bitmap

#c# #.net #растровое изображение

Вопрос:

Итак, у меня есть код, в котором я создаю растровое изображение и графику и использую метод CopyFromScreen для создания скриншота, а затем я продолжаю назначать его в picturebox. Он находится внутри потока, поэтому он продолжает работать. Проблема в том, что потребление оперативной памяти продолжает расти, и если я попытаюсь использовать графику.Dispose() и bitmap.Dispose() выдадут ошибку, потому что в PictureBox ничего не будет отображаться, поскольку ссылка была удалена. Я уже пытался клонировать растровое изображение в другое и удалить оригинал, но результат тот же, объем оперативной памяти все равно увеличивается.

Это скорее вопрос, который я получил, чем полезный проект, но идея в том, что picturebox получает копию всего экрана в реальном времени.

Как я могу обойти это?

Пример кода:

 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);

        }
 

Комментарии:

1. Подумайте об этом: я даю вам 50 долларов на расходы. Вы приходите в магазин, кладете его на прилавок. Прежде чем кассирша забирает его, я хватаю его и поджигаю. Вы все еще можете потратить эти 50 долларов? Нет. Вы делаете то же самое здесь. Вы удаляете изображение, как только передаете его в picturebox (обратите внимание, что вы не создаете копию, когда назначаете его picturebox — это то же самое изображение). Не было бы разумнее избавиться от старого изображения?

2. У Microsoft есть полный пример кода здесь .

Ответ №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();
 }
 

Другой альтернативой было бы проверить, есть ли в picturebox уже изображение, и удалить его перед заменой.

Комментарии:

1. Теперь я понял, большое спасибо! Основная проблема заключалась в том, что я создавал много растровых изображений, когда писал код, который каким-то образом имел смысл в моей голове, lol.

Ответ №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);
    }
}
 

Комментарии:

1. Не будут ли операции в Foo() жаловаться на межпоточные операции? Уверен, что вам нужно это вызвать.

2. @Nyerguds, попробуйте и сообщите мне свои результаты. Я уверен, что вы будете удивлены…

3. @Idle_Mind Это вряд ли ответ на мой вопрос. Никогда не стоит предполагать, что все работает правильно только потому, что один тестовый запуск не дал ошибок. Попробуйте не удалять это и запустить его на пару минут . bmp Вероятно, он продолжит работать. Это не значит, что все в порядке.