Как вы убедитесь, что WPF выпускает большой Bitmapsource из памяти?
-
18-09-2019 - |
Вопрос
Система: Windows XP SP3, .NET 3.5, 4 ГБ ОЗУ, двойной 1,6 ГГц
У меня есть приложение WPF, которое загружает и переходы (с использованием анимаций раскадровки) чрезвычайно большие PNG. Эти PNG в разрешении 8190x1080. Когда приложение запускается, оно кажется кэшируя изображения, а системная память медленно ползет. В конце концов он задыхает систему и бросает OutofmemoryException.
Вот шаги, которые я сейчас предпринимаю, чтобы попытаться решить это:
1) Я удаляю объекты Bitmapsource из приложения
2) Я настраиваю Bitmapsource Bitmapcacheoption None, когда загружаю Bitmapsource
3) Я замерзаю растросию, как только он будет загружен.
4) Я удаляю все ссылки на изображение, которое использует источник, а также любые ссылки на сам источник.
5) Вручную вызов gc.collect () после завершения вышеупомянутых шагов.
В надежде выяснить, почему WPF висит на память для этих изображений, и возможное решение, чтобы убедиться, что память, используемая для их загрузки, правильно восстанавливается.
Решение
Вы, безусловно, проделали большую работу над этим. Я думаю, что основная проблема заключается в том, что Bitmapcacheoption.NONE не предотвращает кэширование основного ратмапдекодера.
В этом есть несколько сложных решений, таких как выполнение GC.Collect (), загрузка 300 небольших изображений из 300 различных URI и снова вызов GC.Collect (), но прост - это прост:
Вместо загрузки из URI просто постройте поток и передайте его конструктору Bitmapframe:
var source = new BitmapImage();
using(Stream stream = ...)
{
source.BeginInit();
source.StreamSource = stream;
source.CacheOption = BitmapCacheOption.OnLoad; // not a mistake - see below
source.EndInit();
}
Причина, по которой это должно работать, заключается в том, что загрузка из потока полностью отключает кеш. Источник верхнего уровня не только кэширован, но и ни один из внутренних декодеров также не кэширован.
Почему Bitmapcacheoption.onload? Это кажется нелогичным, но этот флаг имеет два эффекта: он позволяет кэшировать, если возможно кэширование, и это приводит к возникновению нагрузки при Endinit (). В нашем случае кэширование невозможно, поэтому все, что он делает, приводит к тому, что нагрузка происходит сразу.
Очевидно, вы захотите запустить этот код с вашего потока пользовательского интерфейса, а затем заморозить Bitmapsource, чтобы вы могли перенести его.
Вы также можете задаться вопросом, почему я не использовал Bitmapcreateoptions.ignoreimagecache. Помимо того факта, что кэширование невозможно, без указания URI, игнорирование не полностью игнорирует кеш изображения: оно только игнорирует его для чтения. Таким образом, даже если будет установлено игнорирование, загруженное изображение все еще вставлено в кэш. Разница в том, что существующее изображение в кэше игнорируется.