2009-11-05 5 views
12

System: Windows XP SP3, .NET 3.5, 4GB RAM, Dual 1.6gHzWie stellen Sie sicher, dass WPF große BitmapSource aus dem Speicher freigibt?

Ich habe eine WPF-Anwendung, die extrem große PNGs lädt und übergänge (mit Storyboard-Animationen). Diese PNGs haben eine Auflösung von 8190x1080. Während die Anwendung läuft, scheint es die Bilder zu cachen und der Speicher des Systems schleicht sich langsam nach oben. Schließlich erstickt es das System und löst die OutOfMemoryException aus.

Hier sind die Schritte, die ich zur Zeit versuchen, nehme dieses Problem zu lösen:

1) Ich Entfernen aus der App die Bitmap Objekte

2) Ich habe die Bitmap BitmapCacheOption auf Keine setze, wenn ich laden Die BitmapSource

3) Ich friere die BitmapSource ein, sobald sie geladen ist.

4) Ich lösche alle Verweise auf das Bild, das die Quelle sowie alle Verweise auf die Quelle selbst verwendet.

5) Manuelle Aufrufen von GC.Collect(), nachdem die obigen Schritte abgeschlossen wurden.

In der Hoffnung, herauszufinden, warum WPF auf Speicher für diese Bilder hängt und eine mögliche Lösung, um sicherzustellen, dass der Speicher zum Laden sie ordnungsgemäß wiederhergestellt wird.

Antwort

21

Sie haben sicherlich eine Menge Arbeit daran gearbeitet. Ich denke, das Hauptproblem ist, dass BitmapCacheOption.None nicht verhindert, dass die zugrunde liegenden BitmapDecoder zwischengespeichert werden.

Es gibt mehrere knifflige Lösungen für dieses wie ein GC.Collect tun(), Laden 300 kleine Bilder aus 300 verschiedenen Uris, und ruft GC.Collect() wieder, aber die einfache ist einfach:

statt Laden von einem Uri, bauen gerade einen Bach und übergeben es an Bitmapframe Konstruktor:

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

der Grund dafür arbeiten sollte, dass das Laden von einem Strom vollständig den Cache deaktiviert. Die Quelle der obersten Ebene wird nicht zwischengespeichert, aber auch keiner der internen Dekodierer wird zwischengespeichert.

Warum BitmapCacheOption.OnLoad? Es scheint nicht eingängig zu sein, aber dieses Flag hat zwei Auswirkungen: Es aktiviert das Zwischenspeichern, wenn Caching möglich ist, und es bewirkt, dass die Last bei EndInit() auftritt. In unserem Fall ist das Caching unmöglich, so dass die Last sofort ausgeführt wird.

Offensichtlich möchten Sie diesen Code von Ihrem UI-Thread ausführen und dann die BitmapSource einfrieren, damit Sie sie verschieben können.

Sie können sich auch fragen, warum ich BitmapCreateOptions.IgnoreImageCache nicht verwendet habe. Abgesehen von der Tatsache, dass Caching unmöglich ist und kein URI angegeben wird, ignoriert IgnoreImageCache den Image-Cache nicht vollständig: Er ignoriert ihn nur zum Lesen. Selbst wenn IgnoreImageCache gesetzt ist, wird das geladene Bild immer noch in den Cache eingefügt. Der Unterschied besteht darin, dass das vorhandene Bild im Cache ignoriert wird.

+0

BitmapSource source = new BitmapSource() wird nicht kompiliert und ich bin mir nicht sicher warum. Übergibt diesen Fehler: Fehler Kann keine Instanz der abstrakten Klasse oder Schnittstelle 'System.Windows.Media.Imaging.BitmapSource' – discorax

+0

Ahh..it kompiliert, wenn ich BitmapImage anstelle von BitmapSource verwenden. Nun, wie wird das Probleme verursachen? :) – discorax

+0

Dieser Ansatz sieht bisher vielversprechend aus. Ich werde weiter testen. – discorax

Verwandte Themen