2009-08-26 7 views
6

Ich versuche herauszufinden, wie man einen WriteableBitmap-Speicher freigibt.WPF WriteableBitmap Speicherleck?

Im nächsten Abschnitt des Codes fülle ich den Backbuffer eines Writeablebitmap mit einer wirklich großen Datenmenge von „BigImage“ (3600 * 4800 Pixel, nur zum Testen) Wenn ich die Zeilen kommentieren, wo Bitmap und Bilder erreicht werden zu Null, der Speicher ist nicht freigegeben und die Anwendung verbraucht ~ 230 MB, sogar , wenn Bild und Bitmap nicht mehr verwendet werden!

Wie Sie am Ende des Codes sehen können, muss GC.Collect() aufgerufen werden, um den Speicher freizugeben.

Die Frage ist also, was ist der richtige Weg, um den Speicher freizugeben, der von einem WriteableBitmap-Objekt verwendet wird? Ist GC.Collect() der einzige Weg?

Jede Hilfe wäre großartig.

PS. Entschuldigung für mein schlechtes Englisch.

private void buttonTest_Click(object sender, RoutedEventArgs e) 
{ 
      Image image = new Image(); 
      image.Source = new BitmapImage(new Uri("BigImage")); 

      WriteableBitmap bitmap = new WriteableBitmap(
       (BitmapSource)image.Source); 

      bitmap.Lock(); 

      // Bitmap processing 

      bitmap.Unlock(); 

      image = null; 
      bitmap = null; 

      GC.Collect(); 
} 
+0

http://stackoverflow.com/questions/1534983/how-to-dispose-a-writeable-bitmap-wpf/2422496#2422496 – nyxtom

Antwort

0

Erzwingen eines GC ohne image und bitmap zu null Einstellung wird sie nicht aufzuräumen, weil sie noch vor Ort verwiesen werden und sind somit root Referenzen betrachtet. Dies ist nichts speziell mit der WriteableBitmap und mehr eine Frage, wie GC funktioniert.

Wenn Sie sie nicht auf null setzen und keine Speicherbereinigung erzwingen, werden sie gesammelt, sobald die Methode existiert und ein GC auftritt. Das wird oben empfohlen, indem Sie die Sammlung selbst erzwingen, da Sie wahrscheinlich eher die Leistung beeinträchtigen als ihr zu helfen.

+0

Danke sowohl für Ihre Hilfe. Das Problem ist, dass der Garbage Collector scheint nicht den Speicher von Bild und Bitmap zu sammeln. Wenn ich die Zeilen kommentiere, denen sie null zugewiesen sind, und sobald die Methode die Ausführung beendet hat, bleibt der von der gesamten Anwendung belegte Speicher ~ 234 MB. Scheint wie ein wirklich lästiges Verhalten. Nochmals vielen Dank. – Mario

+0

Bleibt wie lange? Sind Sie sicher, dass der Müllsammler tatsächlich versucht zu sammeln? Öffnen Sie perfmon und beobachten Sie die GC-Zähler, um zu sehen, ob es tatsächlich versucht zu sammeln. Wenn nicht, müssen Sie sich keine Sorgen machen - es gibt keinen Speicherdruck, daher ist der GC nicht erforderlich. –

+0

Vielen Dank für Ihre Hilfe und Geduld. Ich habe GC-Leistungsindikatoren gesehen, und es ist ein niedriges% der Zeit in GC verbracht, aber ich brauche som helfen, die nächsten Daten herauszufinden: #Bytes in allen Haufen 1115176000 #GC Griffe 845.000 #induce GC 5.0 Es scheint, der Aufruf von GC.Collect() ist nicht notwendig, aber die Null-Zuweisung von beiden Objekten (Bild und Bitmap) ist, da der verwendete Speicher bei ~ 234MB bleibt, bis die Anwendung geschlossen wird. – Mario

1

Im Allgemeinen sollte der Speicher nach Bedarf automatisch freigegeben werden.

Dazu müssen Sie jedoch sicher sein, dass das Objekt wirklich nicht genutzt wird: Es dürfen nirgendwo Verweise auf das Objekt existieren, auch nicht "nicht mehr verwendet". Wenn Sie also Ihre WriteableBitmap und die ursprüngliche BitmapSource in Variablen einer langlebigen Klasse platzieren, werden sie erst freigegeben, wenn sich der Container befindet.

Auch WPF verwendet ein beibehaltenes GFX-Modell: Wenn Sie rendern, speichern Sie nur Anweisungen auf wie zu rendern. Die "Anweisungen" zum Rendern einer Bitmap enthalten einen Verweis auf die Bitmap. Wenn Sie also ein großes Bitmap rendern, dann für eine Weile (zumindest solange es auf dem Bildschirm angezeigt wird - selbst wenn die Bildschirmversion winzig ist) Bilder werden beibehalten.

In der Praxis; Speichern Sie Verweise auf diese Bitmaps nur dort, wo sie benötigt werden, und wenn der Kontext, in dem sie sich befinden, langlebig ist (ein langer Methodenaufruf oder ein Methodenaufruf, der einen Abschluss mit einem Verweis auf die Bitmaps oder ein Mitglied eines gelebte Klasse) und setze sie auf null, sobald sie nicht mehr benötigt werden.

Es ist nicht notwendig, den Speicher manuell freizugeben; GC.Collect() sollte überflüssig sein. Als Faustregel kann GC.Collect nur während des Benchmarks verwendet werden, um einen Hinweis auf den Speicherverbrauch zu erhalten und/oder mit einem sauberen Slate zu starten. Die Gesamtleistung wird im Allgemeinen durch Aufrufe von GC.Collect() verringert.