Утилизация изображения в WPF в списке (утечка памяти) - PullRequest
5 голосов
/ 09 октября 2008

У меня есть ListBox с кучей изображений в нем (сделано через табличку с данными). Изображения создаются путем задания источника элементов:

<Image x:Name="ItemImage" Source="{Binding ImageUrl}"/> 

и затем они очищаются с помощью метода Items.Clear () списка. Новые изображения добавляются с помощью метода Items.Add из списка.

Тем не менее, использование памяти только начинает расти вверх и вверх и вверх. Это те же 300 или около того маленьких изображений, которые отображаются, но память никогда не освобождается. Приложение начинает использовать около 40 мегабайт и быстро поднимается до 700 мегабайт. Как освободить память, которую используют все эти изображения?

РЕДАКТИРОВАТЬ : Я забыл упомянуть одну вещь: изображения (размером около 4-5 тысяч) загружаются по сети. Кэширование как-то ответственно за это? Отображение 12 изображений занимает около 10 мегабайт памяти, что примерно в 100 раз превышает размер файла.

Ответы [ 2 ]

4 голосов
/ 09 октября 2008

Как насчет того, чтобы вообще не использовать всю эту память?

( Примечание: Следующий абзац и код воспроизводятся из этого ответа .)

Часть проблемы заключается в том, что он загружает полное изображение в каждом. Вы должны использовать IValueConverter, чтобы открыть каждое изображение в уменьшенном размере, установив свойства DecodePixelWidth или DecodePixelHeight для BitmapImage. Вот пример, который я использую в одном из моих проектов ...

class PathToThumbnailConverter : IValueConverter {
    public int DecodeWidth {
        get;
        set;
    }

    public PathToThumbnailConverter() {
        DecodeWidth = 200;
    }

    public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
        var path = value as string;

        if ( !string.IsNullOrEmpty( path ) ) {

            FileInfo info = new FileInfo( path );

            if ( info.Exists && info.Length > 0 ) {
                BitmapImage bi = new BitmapImage();

                bi.BeginInit();
                bi.DecodePixelWidth = DecodeWidth;
                bi.CacheOption = BitmapCacheOption.OnLoad;
                bi.UriSource = new Uri( info.FullName );
                bi.EndInit();

                return bi;
            }
        }

        return null;
    }

    public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
        throw new NotImplementedException();
    }

}

Вы также можете учитывать IsAsync=True в своем Binding, чтобы преобразователь вызывался в фоновом потоке.

4 голосов
/ 09 октября 2008

Если вы не делаете ничего необычного при загрузке изображений (например, используя самодельные загрузчики изображений или что-то в этом роде), то ГХ должен стереть их для вас, когда ничто больше не ссылается на них.

Держите ли вы где-нибудь ссылки на данные? Помните, что события и обработчики событий могут иногда «обманывать» сборщика мусора, думая, что объект все еще используется:

MyObject obj = new MyObject();
obj.TheEvent += new EventHandler(MyHandler);
obj = null;
// Now you might think that obj is set for collection but it 
// (probably - I don't have access to MS' .NET source code) isn't 
// since we're still listening to events from it.

Не уверен, относится ли это к вам, но, по крайней мере, я бы проверил на вашем месте.

Кроме того, если у вас есть доступ к профилировщику, такому как AQTime или аналогичный, то выполнение кода через него может дать вам несколько советов.

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

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