Я получаю System.OutOfMemoryException. Есть способ сделать мой код легче? - PullRequest
0 голосов
/ 11 декабря 2011

Я хочу написать процедуру, которая получает некоторые jpeg-кадры с сервера (например, с удаленного рабочего стола), преобразует их в растровые изображения и затем отображает их в форме окна.Я пытаюсь сделать процедуру как можно более легкой, но, возможно, я делаю это неправильно, так как всегда получаю исключение System.OutOfMemoryException.Мой код выглядит следующим образом:

РЕДАКТИРОВАТЬ: добавил часть, которая связана с этим исключением

private void WatcherRoutine()
    {
        Boolean lLoopEnd = false;
        Bitmap lCurrent = null;
        //Graphics lGraphics = null;
        Image lImg = null;
        BinaryReader lBRVideo = new BinaryReader(this._state.Video.GetStream());

        while (lLoopEnd == false)
        {
            try
            {
                // Reads frame type
                switch (lBRVideo.ReadByte())
                {
                    // Frame received is a big frame (ie a desktop screenshot)
                    case Constants.BIGFRAME:
                        {
                            // Reads frame size in bytes
                            Int32 lVideoLength = lBRVideo.ReadInt32();
                            if (lVideoLength > 0)
                            {
                                // Stores frame in a stream
                                MemoryStream ms = new MemoryStream(lBRVideo.ReadBytes(lVideoLength));
                                // Creates image from stream
                                lImg = Image.FromStream(ms);
                                ms.Dispose();
                                // Creates bitmap from image
                                lCurrent = new Bitmap(lImg);
                                lImg.Dispose();
                                // Passes image to windows form to display it
                                this.Invoke(this._state.dUpdateVideo, lCurrent);
                                    ////lGraphics = Graphics.FromImage(lImg);
                                    //lGraphics.Dispose();
                            }
                        }
                        break;
                    // Diff frame (ie a small part of desktop that has changed)
                    // Commenting this part makes the exception disappear :|
                    case Constants.DIFFFRAME:
                        {
                            Int16 lX = lBRVideo.ReadInt16(),
                                lY = lBRVideo.ReadInt16();
                            Int32 lVideoLength = lBRVideo.ReadInt32();
                            if (lVideoLength > 0)
                            {
                                //Byte[] lVideoImg = lBRVideo.ReadBytes(lVideoLength);
                                //Image lImgDiff = Image.FromStream(new MemoryStream(lVideoImg));
                                ////if(lGraphics != null)
                                //{
                                //    lGraphics.DrawImage(lImgDiff, lX, lY);
                                //    this.Invoke(this._state.dUpdateVideo, new Bitmap(lImg));
                                //}
                            }
                        }
                        break;
                    case Constants.CURSOR:
                        {
                            Int16 lX = lBRVideo.ReadInt16(),
                                lY = lBRVideo.ReadInt16();
                            // TODO
                        }
                        break;
                    default:
                        break;
                }
            }
            catch (Exception e)
            {
                if (this._state.WorkEnd == false)
                {
                    this._state.WorkEnd = true;
                    this.BeginInvoke(this._state.dDisconnect);
                }
                lLoopEnd = true;
                SmartDebug.DWL(e.Message);
            }
        }
    }

dUpdateVideo является делегатом, который содержит эту небольшую подпрограмму ... возможно я должен освободить pBmp?

private void UpdateVideo(Bitmap pBmp)
    {
        this.VideoPictureBox.Image = pBmp;
    }

Ответы [ 3 ]

2 голосов
/ 11 декабря 2011

Когда вы используете API на основе GDI + (System.Drawing), исключение OutOfMemory не обязательно означает, что у вас недостаточно памяти. Это также может означать, что параметры, переданные в GDI +, являются недопустимыми или по какой-либо другой причине. GDI + довольно OutOfMemory счастлив.


Вам также следует повторно использовать поток памяти, если это возможно. Это снижает давление ГХ много . Вы выделяете много больших объектов, и в этом сценарии GC довольно плохой.


Также я думаю, что вы никогда не выбрасываете lCurrent.


Тогда вы нарушаете договор Image.FromStream:

Вы должны держать поток открытым в течение всего времени жизни изображения:

lImg = Image.FromStream(ms);
ms.Dispose();
lCurrent = new Bitmap(lImg);// `lImage` is used here, but `ms` is already disposed
lImg.Dispose();

Документация для Image.FromStream гласит:

Вы должны держать поток открытым в течение всего времени жизни изображения.

Перемещение ms.Dispose() позади lImg.Dispose()

1 голос
/ 11 декабря 2011

Проблема может быть связана с ошибкой двоичного протокола (длина видео каким-то образом нарушена, см. LBRVideo.ReadInt16 и ReadInt32 вызывает ваш комментарий)

1 голос
/ 11 декабря 2011

Однажды я написал программу, которая обрабатывает множество изображений, загруженных из файлов. Я Dispose сделал все, что мог, как можно скорее, и отдал остальное в ГК. Этого было недостаточно, профилирование использования памяти ясно показало, что сборщик мусора был слишком медленным относительно скорости загрузки изображений моей программы. Решением было вызывать GC.Collect() вручную каждый раз, когда я заканчивал обработку определенного числа изображений. Обратите внимание, что это не очень хорошая практика , но иногда помогает. По крайней мере, стоит попробовать.

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