У меня есть ListBox с кучей изображений (сделано через datatemplate). Изображения создаются путем установки источника элементов:
<Image x:Name = "ItemImage" Source = "{Binding ImageUrl}"/>
а затем они очищаются с помощью метода Items.Clear () списка. Новые изображения добавляются с помощью метода Items.Add списка.
Однако использование памяти только начинает расти и расти. Отображаются те же 300 или около того маленьких изображений, но память, кажется, никогда не освобождается. Приложение начинает использовать около 40 мегабайт и быстро достигает 700 мегабайт. Как мне освободить память, которую используют все эти изображения?
РЕДАКТИРОВАТЬ: Одна вещь, которую я забыл упомянуть, изображения (размером около 4-5k каждое) загружаются по сети. Кеширование как-то отвечает за это? Отображение 12 изображений занимает около 10 мегабайт памяти, что примерно в 100 раз превышает размер файла.





Если вы не делаете ничего необычного при загрузке изображений (например, используете самодельные загрузчики изображений или что-то в этом роде), тогда GC должен стереть их за вас, когда на них больше ничего не ссылается.
Вы где-нибудь держитесь ссылок на данные? Помните, что события и обработчики событий могут иногда «обмануть» сборщика мусора, заставив его думать, что объект все еще используется:
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 или аналогичному, то запуск вашего кода через него может дать вам некоторые подсказки.
Вы также можете попробовать и посмотреть, имеет ли значение какая-либо разница, если вы загружаете изображения с диска или из ресурсов, встроенных в вашу сборку.
Как насчет того, чтобы вообще не использовать всю эту память?
(Примечание: Следующий абзац и код воспроизводятся из этот ответ.)
Part of the problem is that it is loading the full image in each. You have to use an
IValueConverterto open each image in a thumbnail size by setting either theDecodePixelWidthorDecodePixelHeightproperties on theBitmapImage. Here's an example I use in one of my projects...
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, чтобы преобразователь вызывался в фоновом потоке.
Проблема, которую я заметил, заключается в том, что они часто идут с черными или белыми рамками как часть эскиза, что не всегда выглядит хорошо, я полагаю, именно поэтому большинство браузеров изображений, похоже, создают свои собственные хранилища эскизов.
Таким и таким образом браузер может контролировать размер миниатюр.
Или даже лучше - используйте встроенный эскиз, если он существует, поэтому вам даже не нужно читать весь файл и изменять его размер ... Поиск BitmapFrame.Thumbnail