7 Stimmen

WPF WriteableBitmap Speicherleck?

Ich versuche herauszufinden, wie ich einen WriteableBitmap-Speicher freigeben kann.

Im nächsten Abschnitt des Codes fülle ich den Backbuffer einer WriteableBitmap mit einer wirklich großen Menge an Daten aus "BigImage" (3600 * 4800 px, nur zum Testen) Wenn ich die Zeilen auskommentiere, in denen Bitmap und Image gleich Null sind, wird der Speicher nicht freigegeben und die Anwendung verbraucht ~230 MB, selbst wenn Image und bitmap nicht mehr verwendet werden!

Wie Sie am Ende des Codes sehen können, ist es notwendig, GC.Collect() aufzurufen, um den Speicher freizugeben.

Die Frage ist also, was ist der richtige Weg, um den von einem WriteableBitmap-Objekt verwendeten Speicher freizugeben? 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 Stimmen

3voto

Bjarke Punkte 113

Führen Sie Ihren Test unter Windows XP und mit .Net 3.5 SP1 durch? Wenn ja, dann handelt es sich um ein bekanntes Problem, das in Version 4.0 behoben werden wird.

Siehe http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5d88cdf1-e992-4ad4-8f56-b5dbf92dcf1c

2voto

Eamon Nerbonne Punkte 45041

Im Allgemeinen sollte der Speicher bei Bedarf automatisch freigegeben werden.

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

Außerdem verwendet WPF ein beibehaltenes GFX-Modell: Wenn Sie rendern, speichern Sie eigentlich nur Anweisungen auf wie zu machen. Die "Anweisungen" zum Rendern einer Bitmap enthalten einen Verweis auf die Bitmap - wenn Sie also jemals eine große Bitmap rendern, bleiben diese Bilder eine Zeit lang erhalten (zumindest solange sie auf dem Bildschirm zu sehen sind - auch wenn die Version auf dem Bildschirm winzig ist).

In der Praxis: Speichern Sie Verweise auf diese Bitmaps nur dort, wo sie benötigt werden, und wenn der Kontext, in dem sie leben, langlebig ist (ein langer Methodenaufruf oder ein Methodenaufruf, der eine Closure mit einem Verweis auf die Bitmaps erzeugt, oder ein Mitglied einer langlebigen Klasse), dann setzen Sie 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 gilt: Verwenden Sie GC.Collect nur während des Benchmarkings, um einen Hinweis auf den Speicherverbrauch zu erhalten und/oder um mit einer sauberen Weste zu beginnen. Die Gesamtleistung wird im Allgemeinen durch Aufrufe von GC.Collect() verringert.

0voto

Kent Boogaart Punkte 170094

Erzwingen einer GC ohne Einstellung image y bitmap à null bereinigt sie nicht, da sie noch lokal referenziert werden und somit als Root-Referenzen gelten. Dies hat nichts speziell mit dem WriteableBitmap und mehr eine Frage, wie GC funktioniert.

Wenn Sie sie nicht auf null und erzwingen Sie keine Garbage Collection, dann werden sie gesammelt, sobald die Methode existiert und eine GC stattfindet. Das wird empfohlen, über die Erzwingung der Sammlung selbst, weil Sie wahrscheinlich schadet Leistung eher als es zu helfen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X