утечка памяти при сохранении растрового изображения? - PullRequest
4 голосов
/ 21 июня 2011

Я сохраняю скриншот текущего изображения на компьютере:

Rectangle bounds = Screen.GetBounds(Point.Empty);

using (var bitmap = new Bitmap(bounds.Width, bounds.Height))
{
    using (Graphics g = Graphics.FromImage(bitmap))
    {
       g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
    }

    using (var mss = new MemoryStream())
    {
        bitmap.Save(mss,ImageFormat.Gif);
    }
}

И утечка памяти имеет следующий код:

bitmap.Save(mss,ImageFormat.Gif);

Не следует ли мне использовать usingутилизировать все, что я использую?

Почему я все еще получаю действительно высокое использование памяти при съемке большого количества фотографий, а память не возвращается?

Спасибо!

Ответы [ 2 ]

3 голосов
/ 21 июня 2011

Возможно, вы столкнулись с той же проблемой, с которой я столкнулся, когда я задал этот вопрос для SO.

В моем случае проблема заключалась в том, что MemoryStream не высвобождает внутреннее byte[] даже при вызове Dispose на нем.byte[] не освобождается до тех пор, пока MemoryStream не выйдет из области видимости и не будет собран GC.

В этом блоге подробно описывается причина проблемы, а также рабочее решение. Это помогло мне, и я подозреваю, что вы столкнулись с той же проблемой.По сути, он оборачивает базовый MemoryStream в тип, который реализует тот же интерфейс, но при вызове Dispose() устанавливает для ссылки на поток значение null.Поскольку никакие другие объекты не должны иметь оперативную ссылку на внутренний поток, это позволяет ГХ подключиться и очистить его.

Кроме того, эта проблема усугубляется тем фактом, что внутренний byte[], вероятно, будет выделенв куче больших объектов, что приводит к фрагментации после нескольких выделений.

2 голосов
/ 21 июня 2011

Вы можете попробовать использовать BufferManager, он будет управлять байтом [] для вас.

        // declare the BufferManager somewhere. Check thread safety!
        BufferManager bm = BufferManager.CreateBufferManager(qqq, yyy);


        // wrap your current code to use the buffer manager
        Rectangle bounds = Screen.GetBounds(Point.Empty);

        using (var bitmap = new Bitmap(bounds.Width, bounds.Height))
        {
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
            }

            byte[] buffer = bm.TakeBuffer(yyy);
            try
            {
              using (MemoryStream stream = new MemoryStream(buffer))
              {
                 bitmap.Save(mss,ImageFormat.Gif);
              }
            }
            finally
            {
               bm.ReturnBuffer(buffer);
            }
       }
...