Image.RotateFlip утечка памяти: / - PullRequest
6 голосов
/ 07 июля 2011

Хотя я программирую около 11 лет (в основном VB6, последние 6 месяцев C #), это первый раз, когда я на самом деле задаю вопрос :) Я нашел все свои ответы от interwebz, но эту проблему не могу решить себя. Ваш сайт - одно из самых полезных мест, от которых я получил лучшие ответы!

Я покажу код, который я использую (выдержка из того, что имеет значение). Проблема заключается в том, что при использовании метода RotateFlip память быстро увеличивается до ~ 200M, а через некоторое время GC собирает ее. Основной метод, вызывающий его, повторяется около 30 раз в секунду, поэтому производительность здесь крайне важна. Я пытался использовать графическое матричное преобразование, но иногда это не удается и показывает не перевернутое изображение Само приложение основано на использовании веб-камеры, скрытии предварительного просмотра, создании изображения обратного вызова и отображении его в картинке. Затем он накладывает прямоугольник на if из другого класса. Вот причина использования обратного вызова, а не окна предварительного просмотра.

Capture.cs класс:

internal Bitmap LiveImage;

    int ISampleGrabberCB.BufferCB(double bufferSize, IntPtr pBuffer, int bufferLen)
    {
        LiveImage = new Bitmap(_width, _height, _stride, PixelFormat.Format24bppRgb, pBuffer);

        if (ExpImg) // local bool, used rarely when the picture saving is triggered
        {
            LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
            var a = LiveImage.Clone(new Rectangle(Currect.Left, Currect.Top, Currect.Width, Currect.Height),
                                    LiveImage.PixelFormat);
            using (a)
                a.Save("ocr.bmp", ImageFormat.Bmp);

        }
        else // dmnit, rotateflip leaks like h*ll but matrix transform doesn't sometimes flip :S
        {
            LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
            /*using (var g = Graphics.FromImage(LiveImage))
            {
                g.Transform = _mtx;
                g.DrawImage(LiveImage, 0, 0);
            }*/
        }
        GC.Collect(); // gotta use it with rotateflip, otherwise it gets crazy big, like ~200M :O
        return 0;
    }
}

В основной форме у меня есть событие, которое обновляет картинку в картинке:

private void SetPic()
{
    pctCamera.Image = _cam.LiveImage;
    _cam.PicIsFree = false;
}

Поскольку мне нужно получить изображение в главной форме, которая находится в другом классе, я решил, что наиболее логичным является открытое изображение, которое обновляется в каждом кадре обратного вызова. Причина, по которой я не хочу использовать матричное преобразование, заключается в том, что он медленнее, а иногда и с такой скоростью не удается перевернуть изображение, и частота такого поведения сильно отличается на разных ПК с разными аппаратными возможностями и скоростями ЦП, а также с самой быстрой частотой кадров 30fps с 1,2 ГГц CPU показывает это очень часто.

Так, вы можете помочь мне разобраться? На самом деле я не использую его в текущей версии, я использую закомментированное матричное преобразование, потому что мне плохо от использования GC.Collect: (

Спасибо !!!

Ответы [ 3 ]

5 голосов
/ 07 июля 2011
pctCamera.Image = _cam.LiveImage;

Тяжелое использование памяти, которое вы наблюдаете, является верным признаком того, что вы упустили возможность где-то вызвать Dispose (), позволяя неуправляемым ресурсам (в основном памяти), используемым растровым изображением, освобождаться раньше, чем позволяя сборщику мусора делать это. Цитируемое утверждение - один из таких случаев, вы не утилизируете старое изображение, на которое ссылается графическое поле. Исправлено:

if (pctCamera.Image != null) pctCamera.Image.Dispose();
pctCamera.Image = _cam.LiveImage;
1 голос
/ 07 июля 2011

Вы можете переписать свой код следующим образом:

internal Bitmap LiveImage;

int ISampleGrabberCB.BufferCB(double bufferSize, IntPtr pBuffer, int bufferLen)
{
    using (LiveImage = new Bitmap(_width, _height, _stride, PixelFormat.Format24bppRgb, pBuffer))
    {
        LiveImage.RotateFlip(RotateFlipType.RotateNoneFlipY);
        if (ExpImg) // local bool, used rarely when the picture saving is triggered
        {
            var a = LiveImage.Clone(new Rectangle(Currect.Left, Currect.Top, Currect.Width, Currect.Height),
                                    LiveImage.PixelFormat);
            using (a)
                a.Save("ocr.bmp", ImageFormat.Bmp);
        }
    }

    return 0;
}

Bitmap является классом Image и реализует IDispose.Поскольку вы создаете Bitmap каждый раз, я предлагаю использовать оператор using для автоматического освобождения ресурсов.

0 голосов
/ 07 июля 2011

GC.Collect для этой ситуации.Сбор данных является ЕДИНСТВЕННЫМ способом освободить их, и при создании ОГРОМНЫХ растровых изображений это путь.GC.Collect действительно сильно тормозит?

Кроме того, вы должны как можно меньше сохранять количество растровых копий.

...