Как освободить память после того, как BitmapImage больше не нужен? - PullRequest
14 голосов
/ 02 декабря 2011

Сначала я загружаю BitmapImage в Image элемент управления Window.Во-вторых, я работаю с элементом управления Image и затем закрываю Window.

. Я делаю это 2-3 раза в минуту, и моя память заполняется очень быстро, потому что изображения не выгружаются обратно, когдаокно закрыто.

Так как выгрузить BitmapImage из Image.Source управления вручную, чтобы освободить память?

Ответы [ 4 ]

24 голосов
/ 23 октября 2014

Я считаю, что вы ищете решение на http://www.ridgesolutions.ie/index.php/2012/02/03/net-wpf-bitmapimage-file-locking/. В моем случае я пытался найти способ удалить файл после того, как он был создан, но, похоже, это решение обеих проблем.

Не освобождает память:

var bitmap = new BitmapImage(new Uri(imageFilePath));

Освобождает память и позволяет удалить файл:

var bitmap = new BitmapImage(); 
var stream = File.OpenRead(imageFilePath);

bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
stream.Close();
stream.Dispose();

Опционально также может заморозить BitmapImage:

bitmap.Freeze();
3 голосов
/ 04 мая 2017

В моей ситуации кажется, что проблема заключается в кэшировании растрового изображения. Ранее я загружал растровые изображения так:

Bitmap bitmap = new Bitmap();

using(var stream = new FileStream(...))
{
    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.StreamSource = stream;
    bitmap.EndInit();
}

bitmap.Freeze();
image.Source = bitmap;

Постоянная замена image.Source тем же способом, что и при наращивании памяти, принудительное принудительное удаление мусора не помогло.

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

Stream mediaStream;

void DisposeMediaStream()
{
    if (mediaStream != null)
    {
        mediaStream.Close();
        mediaStream.Dispose();
        mediaStream = null;
        GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
    }
}

void Update()
{
    DisposeMediaStream();

    var bitmap = new BitmapImage();
    mediaStream = new FileStream(...);

    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.None;
    bitmap.StreamSource = mediaStream;
    bitmap.EndInit();

    bitmap.Freeze();
    ControlImage.Source = bitmap;
}

Таким образом, я могу циклически перемещаться по тоннам изображений (например, Windows Photo Viewer), и память остается низкой. Обратите внимание, что поток не должен оставаться открытым после того, как изображение действительно отрисовано.

0 голосов
/ 02 декабря 2011

Вы можете установить объект на null, чтобы на объект BitmapImage больше не ссылались.В этой ситуации GC должен позаботиться о высвобождении ресурсов.Вы можете позвонить GC.Collect, но это может повлиять на производительность, если используется слишком часто.

0 голосов
/ 02 декабря 2011

Вы можете вызвать Dispose() на изображениях в событии Closed окна.Я думаю, что также возможно оптимизировать использование памяти, используя различные параметры кэширования.

Редактировать:

Вы не можете вызвать Dispose (), вместо этого вы можете рассмотреть BitmapCacheOption.None.Изображение будет читаться непосредственно с диска и не кэшироваться в памяти.

...