Утечка памяти C # Picturebox

Я просмотрел несколько страниц с похожими запросами, реализовал большинство предложений, но пока не могу найти ничего, что работало бы. Надеюсь, я не упускаю из виду что-то очевидное.

Итак, я использую AForge.net для захвата изображения. Он предоставляет событие, которое запускается для каждого полученного нового кадра, которое в моем коде выглядит так:

private void videoSourcePlayer_NewFrame(object sender, ref Bitmap image)
    {
        framesRecieved++;
        try
        {
            if (!stopCapturing)
            {
                if (pictureBox1.Image != null)
                {
                    pictureBox1.Image.Dispose();
                }
                pictureBox1.Image = image.Clone(new Rectangle(0, 0, image.Width, image.Height), image.PixelFormat);
            }

        }
        catch { }
        finally { GC.Collect(); }
    }

Использование памяти очень стабильно, пока окно остается неподвижным, но как только я беру форму окна и начинаю ее перемещать, использование памяти продолжает расти. Причина, по которой меня заставили поверить, что это может быть связано с окном изображения, заключается в том, что как только я устанавливаю логическое значение «stopCapturing» в значение true, память перестает увеличиваться, даже если я перемещаю окно по экрану. «stopCapturing» не используется ни для чего другого, и событие продолжает запускаться как обычно, единственная разница заключается в том, что изображение отображается в окне изображения. Я не понимаю, в чем причина, поэтому любая помощь будет принята с благодарностью.

PS: Не уверен, связано ли это, но на моей рабочей станции 2 экрана.


person Steven Mills    schedule 21.03.2013    source источник
comment
Начните с удаления пустой защелки и GC.Collect.   -  person Henk Holterman    schedule 21.03.2013
comment
Не уверен в необходимости Clone. Раньше я использовал new Bitmap(image) без проблем.   -  person Ash Burlaczenko    schedule 21.03.2013


Ответы (2)


Bitmap.Clone() выполняет неглубокую копию, фактические байты по-прежнему принадлежат вызывающей стороне, поэтому это потенциально может вызвать всевозможные проблемы. Вам нужно сделать глубокую копию.

Например, AForge:

Bitmap bmp = AForge.Imaging.Image.Clone(image);

Или способ GDI + (также можно использовать биты блокировки и т. Д. Для улучшения производительности):

Bitmap bmp = new Bitmap(image.Width, image.Height, image.PixelFormat);
Graphics g = Graphics.FromImage(bmp);
g.DrawImageUnscaled(image, Point.Empty);
person Joan Charmant    schedule 21.03.2013

Мне интересно, зачем вы вообще клонируете изображение. Мне кажется, что вы должны выделять новое изображение только тогда, когда либо pictureBox1.Image имеет значение null, либо когда размеры или формат пикселей изображения меняются:

private bool BitmapChanged(Bitmap old, Bitmap new)
{
    return old == null || old.PixelFormat != new.PixelFormat ||
        old.Width != new.Width || old.Height != new.Height;
}

private Bitmap MakeSimilarBitmap(Bitmap source)
{
    Bitmap copy = new Bitmap(source.Width, source.Height, source.PixelFormat);
    return copy;
}

private void DrawOnto(Image im, Bitmap source)
{
    using (Graphics g = Graphics.FromImage(im)) {
        g.DrawImage(source, 0, 0);
    }
}

затем, когда вы получите фрейм, вы сделаете что-то вроде этого:

Image im = BitmapChanged(pictureBox1.Image as Bitmap, srcBmp) ?
                          MakeSimilarBitmap(image) : pictureBox1.Image;
DrawOnto(im, srcBmp);
bool same = im == pictureBox1.Image;
if (same)
    pictureBox1.Invalidate();
else {
    Image old = pictureBox1.Image;
    pictureBox1.Image = im;
    old.Dispose();
}
person plinth    schedule 21.03.2013
comment
Вам нужно сделать копию, потому что изображение принадлежит VideoSource. Он будет утилизирован по своему усмотрению. См. Также: aforgenet.com/framework/docs / html / - person Joan Charmant; 22.03.2013
comment
Я хочу сказать, что вы копируете содержимое в одно сохраненное растровое изображение, а не выделяете новую копию в каждом кадре. - person plinth; 22.03.2013