¿Cómo se asegura de que WPF libere BitmapSource de memoria?

Sistema: Windows XP SP3, .NET 3.5, 4GB RAM, Dual 1.6gHz

Tengo una aplicación WPF que carga y transiciones (usando animaciones Storyboard) PNG extremadamente grandes. Estos PNG tienen una resolución de 8190×1080. A medida que la aplicación se ejecuta, parece que almacena en caché las imágenes y la memoria del sistema avanza lentamente. Eventualmente, estrangula el sistema y lanza OutOfMemoryException.

Aquí están los pasos que estoy tomando para tratar de resolver esto:

1) Estoy eliminando los objetos de BitmapSource de la aplicación

2) Estoy configurando BitmapSource BitmapCacheOption en None cuando cargo el BitmapSource

3) Estoy congelando BitmapSource una vez que está cargado.

4) Elimino todas las referencias a la Imagen que usa la fuente, así como cualquier referencia a la fuente misma.

5) Llamar manualmente a GC.Collect () después de que se hayan completado los pasos anteriores.

Esperando descubrir por qué WPF está colgado en la memoria para estas imágenes y una posible solución para asegurar que la memoria utilizada para cargarlas se recupere adecuadamente.

Ciertamente has puesto mucho trabajo en esto. Creo que el principal problema es que BitmapCacheOption.None no evita que los BitmapDecoder subyacentes se almacenen en caché.

Hay varias soluciones difíciles para esto, como hacer un GC.Collect (), cargar 300 imágenes pequeñas de 300 Uris diferentes y llamar a GC.Collect () de nuevo, pero el sencillo es sencillo:

En lugar de cargar desde un Uri, solo construye un Stream y pásalo al constructor de BitmapFrame:

var source = new BitmapImage(); using(Stream stream = ...) { source.BeginInit(); source.StreamSource = stream; source.CacheOption = BitmapCacheOption.OnLoad; // not a mistake - see below source.EndInit(); } 

La razón por la que esto debería funcionar es que la carga de una secuencia deshabilita por completo la caché. No solo la fuente de nivel superior no está en la memoria caché, sino que tampoco ninguno de los decodificadores internos está en la memoria caché.

¿Por qué BitmapCacheOption.OnLoad? Parece contradictorio, pero este indicador tiene dos efectos: habilita el almacenamiento en caché si el almacenamiento en caché es posible y causa que la carga suceda en EndInit (). En nuestro caso, el almacenamiento en caché es imposible, por lo que todo lo que hace causa que la carga suceda de inmediato.

Obviamente, querrá ejecutar este código fuera de su subproceso de interfaz de usuario, luego congelar BitmapSource para que pueda moverlo de nuevo.

También puede preguntarse por qué no usé BitmapCreateOptions.IgnoreImageCache. Aparte del hecho de que el almacenamiento en caché es imposible cualquiera sin URI dado, IgnoreImageCache no ignora por completo el caché de imagen: solo lo ignora para leer. Entonces, incluso si IgnoreImageCache está configurado, la imagen cargada aún se inserta en la caché. La diferencia es que la imagen existente en el caché se ignora.