meine Frage betrifft die Speicherfreigabe unter VB.NET mit FW 2.0 und 4.0
Als Annahme sei folgende einfache Objektstruktur deklariert:
Public Class Rack Public Name As String Public Number As Integer Public Shelves As Dictionary(Of String, Shelf) End Class
Public Class Shelf Public Name As String Public Number As Integer Public Books As Dictionary(Of String, Book) End Class
Public Class Book Public Name As String Public Number As Integer Public Chapters As Dictionary(Of String, Chapter) End Class
Public Class Chapter Public Name As String Public Number As Integer Public Pages As Dictionary(Of String, Page) End Class
Public Class Page Public Number As Integer Public Contents As String End Class
Der Aufruf einer Funktion GetRackContents(Name As String) As Rack liefert mir nun den Inhalt des gewünschten Racks zB im Objekt myRack zurück - myRack enthält dann viele Shelves, die noch mehr Bücher, Kapitel und Seiten enthalten. Gut soweit.
Wenn nun die Verwendung von myRack abgeschlossen ist und ich das Objekt nicht mehr brauche, was ist dann tatsächlich zu tun, um den Speicher (inklusive aller untergeordneter Objekte) wieder freizugeben? Sollte ich a.) myRack durch Verlassen seiner Deklarationsumgebung einfach out of scope gehen lassen - die GC macht dann schon alles nötige b.) myRack vor Verlassen seiner Deklarationsumgebung zumindest auf Nothing setzen c.) zumindest die in den einzelnen Objekten enthaltenen Dictionaries mit .Clear() leeren d.) vor dem Leeren der in den einzelnen Objekten enthaltenen Dictionaries explizit auch die enthaltenen Objekt auf Nothing setzen
Meine Vermutung: richtig ist Antwort "a". Alles andere ist zwar nicht falsch, ist aber genau genommen unnötig und kostet vor allem Prozessorzeit. Aber ich würde es gerne genau wissen, und so bitte ich um Antwort von jemanden, der es wirklich weiß!
Vielen Dank vorab schon aus dem strahlend sonnigen Wien, Robert ;-)
a.) Ja. Wenn keine Referenzen mehr auf das Objekt vorhanden sind, wird es irgendwann vom GC entfernt. Wenn es keine sonstigen Referenzen auf die Elemente im Dictionary gibt, werden diese auch collected. b.) Was soll das bringen? c.) siehe b. d.) siehe c.
<rant>Irgendwelche lokalen Variablen auf Nothing setzen unmittelbar bevor diese out of scope gehen ist so eine Unart, die VB6 Programmierer immer in VB.Net machen...</rant>
Danke für's Feedback! Wie du richtig vermutest ist das eine Unart, die sich aus (sehr) alten VB6 Tagen erhalten hat (wo das aber teilweise wirklich sehr wichtig war)
Das Problem ist das "irgendwann vom GC entfernt" ...
Ich habe die Erfahrung gemacht, dass gerade bei großen Anwendungen mit vielen Formularen, der Garbage Collector einfach zu spät aufräumt und die Anwendung zu "fett" wird.
Wir die Klasse komplexer um nutzt zum Beispiel Fremdkomponenten / Handler solltest Du dringend in deinem Objekt aufrufen lassen. Dazu einfach selbst Dispose implementieren und aufräumen. Es gibt hier andere Threads in denen einem klar wird, was passieren kann wenn man sich darauf verlässt das der GC alles alleine geregelt bekommt wenn die Objekte OOS laufen.
-mblaess: Danke für den Hinweis, aber nach Lesen diverser Beiträge zur GC scheue ich die Verwendung von .Collect: die Konklusio dieser Artikel ist durchgängig die, dass man das Framwork lieber selber Ordnung halten lassen soll wenn man sich nicht wirklich gut mit dessen Mechanismen auskennt, da man sonst leicht Objekte in die 2te Generationen bugsiert und sich so schnell ein Speicherproblem an anderer Stelle eröffnet...
@Robert: Wenn Du steuern willst wann der Speicher wieder freigegeben wird, bleibt Dir nur der Aufruf von GC.Collect(). Genau dazu kann man diese Funktion überhaupt aufrufen. Es gibt diverse Scenarien wo man den manuellen Aufruf benötigt.
Beachte, dass deine Methode üblicherweise lediglich eine flache Kopie eines Racks zurück gibt. Der Speicherverbrauch für den Verweis ist zu vernachlässigen.
Hallo Wolfgang, darf ich nachfragen wie du das genau meinst? Der Verweis auf das Rootergebnis "Rack" braucht natürlich kaum Speicher (4 Byte auf einem 32 Bit System), mit allen Subverweisen auf Details summiert sich aber der Bedarf: wenn das Rack nur 100 Shelves mit jeweils 100 Books und jeweils 100 Chapters mit jeweils 100 Pages enthält habe ich schon 100.000.000 Detail-Objektverweise (ca. 400 MB), plus 1.010.101 Dictionary-Verweise (ca. 4 MB), d.h. ca. 404 MB OHNE der eigentlichen Detaildaten... und dieser Speicher sollte natürlich asap nach Verwendung wieder als verfügbar erkannt werden.
Hi Robert, du solltest auch mal drüber nachdenken, ob es wirklich notwendig ist, diese Menge an Daten überhaupt in den Speicher zu ziehen. Es gibt viele Alternativen, die hier helfen könnten, z.B. eine Datenbank, ein eigener Filecontainer (z.b. über MemoryMappedFile), ... Ein User Deines Tools würde von dieser Datenflut sicher auch erschlagen werden. Normalerweise betrachten User immer nur Teile der Daten gleichzeitig und eine Navigation in der Gesamtmenge kann man auch anders erreichen, als die Struktur komplett im Speicher aufzubauen.
@ffordermaier: natürlich hast du Recht und die Bearbeitung einer solchen Datenmenge ist ja gar nicht mein Anliegen - das war lediglich ein Beispiel, um meiner Frage über Speicherfreigabe von Objekten (die weitere verschachtelte Verweise enthalten) einen Rahmen zu geben.