XNA - Memory Leak?
-
Hallo zusammen,
ich entwickle gerade ein kleines XNA-Computerspiel mit XNA und C#.
Nun habe ich das Problem, dass der Speicherbedarf langsam aber sicher ansteigt.
Um sicherzustellen, dass der Speicherzuwachs ein Memory Leak ist, habe ich in der Update-Routine von XNA (wird immer wieder aufgerufen) ein GC.Collect(); eingefügt. Trotzdem besteht der Memory Leak immer noch.
Ich vermute, dass das Problem mit der Verwendung von Rendertarget2Ds zusammenhängt, die ich aber im Destruktor einer Wrapper-Klasse Dispose:class Surface { RenderTarget2D RenderTarget; public Surface() { RenderTarget = new RenderTarget(/*...*/); } ~Surface() { RenderTarget.Dispose(); } }
Diese Surface wird öfter verwendet und dann dem GC überlassen.
Ich kann leider nicht den ganzen komplexen Code hier posten, aber wenn sich jemand damit auskennt, wäre ich für Lösungen/Lösungsvorschläge sehr dankbar... Memory Leaks sind schwerer zu knacken als StackOverflows
Liebe Grüße
paulrei
-
-
@Zeus: Tut mir Leid, irgendwie will das mit Dispose bei mir nicht. Danke für die schnelle Antwort
, aber ich weiß nicht genau, was du meinst...
Wie müsste ich RenderTarget denn disposen? Soll ich mit Surface IDisposable implementieren, und wenn ja, bin ich mir immer noch nicht so sicher, wie ich das machen soll...
-
paulrei schrieb:
Soll ich mit Surface IDisposable implementieren, und wenn ja, bin ich mir immer noch nicht so sicher, wie ich das machen soll...
Ja, Surface soll IDisposable implementieren. Ich denke man kann gut sagen, dass ein Objekt, welches ein anderes Objekt besitzt das IDisposable implementiert, auch IDisposable implementieren soll.
paulrei schrieb:
Wie müsste ich RenderTarget denn disposen?
Indem Du Surface disposed. Im Dispose(..) von Surface wird dan Dispose() des RenderTarge Objekts aufgerufen.
Natürlich sind da noch die Details mit dem Finalizer - die sind unter folgendem Link auf ersichtlich. Siehe hier wie IDisposable implementiert wird:
http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
-
Vielen Dank, ich baue mal IDisposable ein.
Ich habe nun mal ein leeres XNA-Projekt im Taskmanager beobachtet (in Update() noch ein GC.Collect(3, GCCollectionMode.Forced)). Hier steigt der RAM zwar langsamer an, aber er steigt ebenfalls. Trotz GC.Collect und leerem Projekt. Ich kann mir das nicht erklären.
-
Der Task Manager gibt dir keinen genügenden Einblick in die Memory Verwaltung. Ev. der Process Explorer (Sysinternals) oder besser grad einen Memory Profiler.
-
paulrei schrieb:
Hier steigt der RAM zwar langsamer an, aber er steigt ebenfalls.
Über welchen Zeitraum? 5 Minuten? 50 Minuten? 5 Stunden? Es liegt in der Natur einer GC das die sich erst mit der Zeit auf einen Speicherbedarf "einpegelt". Dies ist kein Fehler und kein Leak.
Auch hat Dispose wenig mit Memory-Leaks zu tuen. Hierbei geht es nur darum nicht mehr benötigte (unmanaged) Resourcen gezielt freizugeben anstatt auf die GC zu warten. Grundsätzlich freigegeben würden diese Resourcen aber eh früher oder später.
paulrei schrieb:
Ich kann mir das nicht erklären.
Dann beschäftige Dich mal genauer mit der Arbeitsweise einer GC. Der erste (und häufigste) Denkfehler ist, das in einer GC Speicher gelöscht wird wenn er nicht mehr gebraucht wird. Das ist aber FALSCH. Speicher wird nur dann freigegeben wenn neuer Speicher benötigt wird. Solange der Freispeicher einer App ausreicht wird die GC nicht laufen. Erst wenn der Freispeicher der App zur Neige geht versucht diese durch einen GC-Lauf Garbage loszuwerden. Geht das nicht wird einer weiterer Block Speicher vom System geholt. Im Taskmanager sieht man aber nur den zugewiesenen Speicher, man sieht nicht wieviel % davon benutzt werden und wieviel noch frei sind.
Zu GC-Collect():
Mit dieser Methode kann versucht werden, den gesamten Speicher freizugeben, auf den nicht zugegriffen werden kann. Allerdings garantiert die Collect-Methode nicht, dass der gesamte Speicher freigegeben wird, auf den nicht zugegriffen werden kann.
Beachten: da steht "kann". Collect aufzurufen bedeutet also nicht zwingend das dann aller Speicher aufgeräumt wird. Am besten die Finger davon lassen damit die GC ihre Arbeit machen kann.Mit GC.Collect() löst Du keine Speicherprobleme, Du erzeugt nur Performanceprobleme.