PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Memory Leak VB.NET Windows 8 Store App


dax13
2013-04-17, 10:03:53
Hallo zusammen!
Ich habe folgendes Problem:
Ich programmiere eine Windows Store App für Windows 8 und kann Objekte nicht vollständig zerstören. Nämlich, wenn ich die auf "Nothing" setze (null/NULL), dann werden sie nicht vom Speicher gelöscht.
Ich habe bereits bei Microsoft angerufen und gefragt , was ich machen soll. Sie sagen ich alle Referenzen löschen und alle Events, die auf die Objekte referenziert sind deregistrieren. Ich habe die Anweisungen von Microsoft befolgt und trotzdem , wenn ich zwischen 2 Masken im Programm wechsle, nimmt das Programm an Speicher zu.
Kennt sich jmd aus? Kann mir jmd helfen?
bin echt mit meinem Latein am Ende.

Gohan
2013-04-17, 10:09:00
Implementiert das betreffende Objekt IDisposable? Ansonsten noch ein Kommentar den ich auf stackoverflow gefunden habe, der ganz passend ist zu deiner Frage:

"I have two cats. One of them is black, the other is white. Both are fine, but when someone tries to feed the white one the black one will suddenly burst into flames". Can you see the reason for the cat incineration? Neither can we see the reason for your error, since we have no idea about your VisualBasic cats. Add code, provide a short example.

FlashBFE
2013-04-17, 10:29:47
Also nur zur Klarstellung vorneweg: .NET verwendet einen Garbage-Collector, der nur nach Gutdünken aufräumt. Wenn du eine Objektvariable auf Nothing setzt und alle anderen Verweise weg sind, beendet der GC das Objekt nicht sofort, wenn noch genug freier RAM da ist. Die Objektzerstörung auf diesem herkömmlichen Weg (der GC ruft .Finalize im Objekt auf) ist nicht deterministisch und eher für die vielen kleinen normalen Objekte geeignet.

Wenn du aber ein Objekt mit richtig viel Speicherplatz hast, den du nach der Benutzung explizit wieder freigeben willst, solltest du die zweite Variante der Objektzerstörung verwenden: Das Dispose-Schema. Einfach in das Objekt tippen tippen:

Class MeineKlasse
Implements IDisposable<Enter!>

End Class


Beim Enter drücken fügt VS automatisch ein Codesnippet mit einer kompletten Region ein, die das Dispose-Muster abbildet:

#Region "IDisposable Support"
Private disposedValue As Boolean ' So ermitteln Sie überflüssige Aufrufe

' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: Verwalteten Zustand löschen (verwaltete Objekte).
End If

' TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalize() unten überschreiben.
' TODO: Große Felder auf NULL festlegen.
End If
Me.disposedValue = True
End Sub

' TODO: Finalize() nur überschreiben, wenn Dispose(ByVal disposing As Boolean) oben über Code zum Freigeben von nicht verwalteten Ressourcen verfügt.
'Protected Overrides Sub Finalize()
' ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.
' Dispose(False)
' MyBase.Finalize()
'End Sub

' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.
Public Sub Dispose() Implements IDisposable.Dispose
' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(disposing As Boolean) Bereinigungscode ein.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region

Hier löschst du an der passenden Stelle deine Objekte, wahrscheinlich verwaltete Objekte. Große Arrays ersetzt du durch leere Arrays (meinArray = {}) und beendest anderen Kram.

Was hat nun der ganze Spaß gebracht? Du kannst nun von außerhalb deterministisch dein Objekt auf Anweisung zerstören. Dazu rufst du einfach .Dispose auf oder, noch besser, benutzt das Using-Schlüsselwort:


Using MeinObjekt As New MeineKlasse 'Konstruktor wird aufgerufen
MeinObjekt.Prozedur1 'Viel Speicher wird belegt
MeinObjekt.Prozedur2 'Viel Speicher wird belegt
End Using 'Dispose wird aufgerufen

PatkIllA
2013-04-17, 11:03:24
Durch Dispose wird mitnichten das Objekt zerstört. Das bleibt weiterhin solange erhalten wie es Referenzen dazu gibt. Je nach Implementierung werden höchstens Referenzen zu Objekten freigegeben, die dann vom Garbage Collector freigegeben werden können. Den ursprünglichen Leak hat man damit in keinster Weise behoben. Er ist nur nicht mehr so gravierend.


Finalize wird normalweise gar nicht aufgerufen. Dazu muss man das explizit überschreiben und ist vor allem zum aufräumen von unmanaged Resourcen notwendig.

An manchen Stellen ist es sehr unpraktisch Referenzen freizugebben. Da kann man mit WeakReferences arbeiten.

Desweiteren gibt es Tools mit denen man rausbekommen kann, wo noch Referenzen zu Objekten gehalten werden.

dax13
2013-04-17, 11:26:31
Danke für die schnelle Antwort!

Ich kann/darf leider nicht viel vom SourceCode hier posten, da es mir nicht gehört. Ich arbeite nur dran. Das IDisposable Interface war auch zuerst meine Überlegung. Ich habe in Microsoft Foren gelesen, dass die Schnittstelle benutzt werden sollte, wenn eine API/DLL oder lange Listen in Klassen benutzt werden. Andererseits wird man immer abgeraten diese Schnittstelle überall zu benutzen. Ich kann es ja mal testen.

PatkIllA
2013-04-17, 11:40:40
Die Objekte werden weiter existieren und mit an Sicherheit grenzender Wahrscheinlichkeit hast du noch Referenzen. Gerade mit Events und lambda Ausdrücken baut man sich sowas oft unbewusst.

FlashBFE
2013-04-17, 12:03:41
Durch Dispose wird mitnichten das Objekt zerstört. Das bleibt weiterhin solange erhalten wie es Referenzen dazu gibt. Je nach Implementierung werden höchstens Referenzen zu Objekten freigegeben, die dann vom Garbage Collector freigegeben werden können. Den ursprünglichen Leak hat man damit in keinster Weise behoben. Er ist nur nicht mehr so gravierend.
Das Objekt selbst nicht, aber der Programmierer kümmert sich im Dispose drum, dass alle speicherfressenden Unterobjekte entsorgt werden. Das Hauptobjekt bleibt dann nicht mehr störend als leere Hülle zurück und wartet auf den GC.

Finalize wird normalweise gar nicht aufgerufen. Dazu muss man das explizit überschreiben und ist vor allem zum aufräumen von unmanaged Resourcen notwendig.
Richtig, wenn es nichts aufzuräumen gibt, lässt man es einfach weg. Aber wenn man schon ein Speicherproblem hat, sollte man den Unterschied zwischen beiden Varianten kennen lernen.

Andererseits wird man immer abgeraten diese Schnittstelle überall zu benutzen. Der Nachteil des Dispose-Schemas ist, dass Rechenzeit sofort zum Aufräumen eingesetzt wird, während beim Finalize, wenn man es denn benutzt, der GC auf einen günstigeren Moment wartet. Man kann also Performanceeinbußen bekommen. Bei Klassen, die sehr schnell und viel instanziiert und wieder zerstört werden, wäre das eher unpraktisch. Bei deinem Problem trifft das aber nicht zu.

dax13
2013-04-17, 12:17:30
Die Objekte werden weiter existieren und mit an Sicherheit grenzender Wahrscheinlichkeit hast du noch Referenzen. Gerade mit Events und lambda Ausdrücken baut man sich sowas oft unbewusst.

Also, wenn ich dann die Page/Frame Events benutze habe ich dann automatisch dieses Problem? Ich dachte, wenn man in Windows 8 Frame.Navigate(....) aufruft , dass dann die Page auf null gesetzt wird und somit übergeben wird an den GC, sofern keine Referenzen vorhanden sind.

.. Ich habe PerfView benutzt um den Leak zu analysieren. Dabei habe ich einn Dump beim Start des Programms gemacht und ein Dump nachdem Leak.

Und die Liste kam dabei heraus (Nach Aufrufanzahl geordnet).

Name
[RCW Windows.Storage!Windows.Storage.StorageFolder RefCnt: 1]
LIB <<mscorlib!System.Threading.OverlappedData>>
[CCW for togo.Data.AdresseKachel RefCnt: 21]
[local var]
LIB <<System.Xml.Linq!System.Xml.Linq.XHashtable.XHashtableState>>
[RCW Windows.Storage!Windows.Storage.ApplicationData RefCnt: 20]
[RCW Windows.UI.Xaml!Windows.UI.Xaml.Controls.Frame RefCnt: 9]
LIB <<mscorlib!System.Threading.ThreadPoolWorkQueueThreadLocals>>
[Strong handle]
LIB <<mscorlib!System.Text.StringBuilder>>
LIB <<mscorlib!System.Threading.Thread>>
LIB <<mscorlib!System.Threading.TimerQueueTimer>>
LIB <<mscorlib!System.Collections.Hashtable.SyncHashtable>>
[CCW for System.Collections.ObjectModel.ObservableCollection RefCnt: 3]
[CCW for System.Runtime.InteropServices.WindowsRuntime.ICustomPropertyProviderProxy RefCnt: 1]
[CCW for togo.Data.AdresseKachel RefCnt: 26]
LIB <<mscorlib!System.Threading.Tasks.Task.DelayPromise>>
LIB <<mscorlib!List<System.Net.Sockets.DynamicWinsockMethods>>>
emis.togo!emis.togo.emisClass.VB$StateMachine_86_LadeAlleBilder
LIB <<System.ServiceModel!System.ServiceModel.OperationContext.Holder>>
LIB <<System!System.Net.LazyAsyncResult.ThreadContext>>
LIB <<mscorlib!System.Threading.Tasks.StackGuard>>
LIB <<mscorlib!System.Threading.TimerHolder>>
LIB <<System.Xml.Linq!System.Xml.Linq.XNamespace>>
LIB <<System.Xml.Linq!System.Xml.Linq.XName>>
LIB <<mscorlib!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner>>
LIB <<mscorlib!System.Runtime.InteropServices.WindowsRuntime.ICustomPropertyProviderPr oxy>>
togo!togo.Data.AdresseKachel

------------------------------------------------------

Nur ist halt jetzt die Frage, was ich damit anfangen kann.. Ich habe nie etwas damit gemacht :confused:

PatkIllA
2013-04-17, 12:29:27
Events können auf verschiedene Weisen implementiert werden.
Beim einfachsten gibt es ein MulticastDelegate, was dann auch die Referenzen zu den Objekten hält. Und es reicht ja wenn es über eine Kette von Referenzen noch wo dran hängt.

Statische Variablen oder Events sind auch eine potentielle Quelle von Memory Leaks. Von sowas würde auch ich aus diversen Gründen Abstand nehmen.

Ich kenne aber jetzt nicht die Einzelheiten zu den Windows 8 Apps.