Как освободить память после того, как BitmapImage больше не нужен?

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

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

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

Ответ 1

Я считаю, что решение, которое вы ищете, находится на 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();

Ответ 2

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

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), а память остается низкой. Обратите внимание, что поток не должен оставаться открытым, как только изображение действительно отображается.

Ответ 3

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

Ответ 4

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

Edit:

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