frage zur garbagecollection
-
~MyListEntry() { nTestEntry=0; }
Was für einen Sinn macht dieser Destruktor? Lass ihn doch bitte einfach weg.
-
Hallo,
ich hätte da auch noch ein paar Frage zu dem GC bzw. der
Speicherfreigabe in C#.In einem konkreten Projekt lade ich in eine PictureBox eine
von mir erstellte Bitmap.
dies sieht ungefähr so aus.Bitmap bmp = new Bitmap ( 800, 600); Graphics graphics = Graphics.FromImage( bmp ); graphics.Clear ( Color.Red); myPictureBox.Image = bmp;
Wenn ich dies nun öfter in dem Programm mache, sehe ich
im Taskmanager wie der Speicher bis zum Anschlag belegt wird.
Und bei etwa 180 MB, bekomme ich dann eine Systemnachricht,
das nicht mehr genügend virtuellen Speicher zur Verfügung steht
und mein Programm stürzt ab.Meine Fragen wären nun:
Was mache ich falsch?
Wie könnte ich es besser machen?Links, SuchBegriffe in der MSDN etc. würden mir auch weiterhelfen.
-
[Theorie]
Das Bitmap-Objekt verwaltet seinen Speicher selbst und gibt ihn erst frei, wenn es zerstört wurde. Es wird jedoch nie vom GC aufgefressen, weil der in seinem Heap noch genügend Platz hat (das Bitmap-Objekt selber ist ja nicht groß, nur der Speicher, den es noch belegt) und deshalb nicht aktiv wird.
Solche Klassen implementieren deshalb das Interface IDisposable (heisst das so?), damit man sie manuell über die Methode Dispose() zerstören kann, oder zumindest das Objekt auffordern kann, seinen Speicher freizugeben.
Wohlgemerkt, der GC würde das schon machen, aber erst wenn IHM der Speicher ausgeht. Er weiss ja nicht, was das Bitmap Objekt sonst noch für Sachen macht.
[/Theorie]
Am besten, du machst dich mal über die verwendete Bitmap-Klasse schlau. Du kannst auch den GC manuell aufrufen, wenn du weisst, dass du ab jetzt die Bitmap Objekte nicht mehr referenzierst. Das machst du mit System.GC.Collect() oder mit System.GC.Collect(generation).
Übrigens ist mir nicht klar, wasGraphics graphics = Graphics.FromImage( bmp ); graphics.Clear ( Color.Red);
diese zwei Zeilen bezwecken sollen.
-
±ƒ§Ä{£ (Müll)
-
krampfader,
krampfader schrieb:
Wenn ich dann ein objekt aus der Hashtable bzw. liste entferne, möchte ich dass dieses dann auch (wenn möglich) destruktiert wird.
Du kannst grundsätzlich keine Annahmen über den Zeitpunkt der Zerstörung eines Objektes machen - selbst dann nicht, wenn Du explizit GC.Collect() aufrufst. Ob ein Objekt zerstört wird, hängt im wesentlichen von seiner Langlebigkeit ab. Und noch etwas ist in diesem Zusammenhang wichtg: wenn Du selbst eine Finalisierungs-Methode schreibst (~MyListEntry), führt das dazu, daß das Objekt erst eine Speicherbereinigung später durch den GC zerstört wird, da bei der ersten Bereinigung die Finalisierungs-Methode aufgerufen werden muß und das Objekt erst beim nächsten Durchlauf in der Liste der anderen "normalen" zu zerstörenden Objekte landet.
Bashar schrieb:
bei Java ist es jedenfals unbestimmt, ob Finalizer am Programmende aufgerufen werden
...werden sie bei DotNet nicht, glaube ich. Man kann das Aufrufen zwar mit System.GC.RequestFinalizeOnShutdown() erzwingen. Das kostet dann aber etwas mehr Zeit beim Beenden des Programmes.
CSharpCoder schrieb:
Wenn ich dies nun öfter in dem Programm mache, sehe ich
im Taskmanager wie der Speicher bis zum Anschlag belegt wird.Der Thread, in dem der GC läuft, versucht bei günstigen Gelegenheiten Speicherbereinigungen auszuführen - also z.B. dann, wenn das Program gerade auf eine Nutzer-Eingabe wartet. Wenn Du also sehr schnell immer wieder neue Objekte erzeugst gibst Du dem GC weniger Möglichkeiten dazu und es entsteht eine Art Wettbewerb: Wer ist schneller, der GC mit dem Zerstören oder Du mit dem Neuerstellen? Wenn Du also genau weißt, daß Du massiv neue und kurzlebige Objekte erzeugst, bietet sich das explizite Aufrufen von GC.Collect() an, wann immer Du das für sinnvoll erachtest. Sind die Objekte kurzlebig, ist die Wahrscheinlichkeit hoch, daß Sie bei der Bereinigung tatsächlich zerstört werden. Wenn diese Objekte langlebig sind, mußt Du Dir halt mehr Speicher kaufen ;).
----- Edit -----
Es gibt dazu ein interessantes Kapitel in einem guten c# Online-Buch.
-
Der Thread, in dem der GC läuft, versucht bei günstigen Gelegenheiten Speicherbereinigungen auszuführen - also z.B. dann, wenn das Program gerade auf eine Nutzer-Eingabe wartet. Wenn Du also sehr schnell immer wieder neue Objekte erzeugst gibst Du dem GC weniger Möglichkeiten dazu und es entsteht eine Art Wettbewerb: Wer ist schneller, der GC mit dem Zerstören oder Du mit dem Neuerstellen? Wenn Du also genau weißt, daß Du massiv neue und kurzlebige Objekte erzeugst, bietet sich das explizite Aufrufen von GC.Collect() an, wann immer Du das für sinnvoll erachtest. Sind die Objekte kurzlebig, ist die Wahrscheinlichkeit hoch, daß Sie bei der Bereinigung tatsächlich zerstört werden.
Das stimmt so nicht. Die Reinigung wird genau dann durchgeführt, wenn kein neues Objekt allokiert werden kann oder wenn du es anforderst.
Es entsteht auch kein Wettrennen. Während der Reinigung wird der Heap umgeschichtet und deshalb kann kein Thread solange auf Objekte zugreifen oder gar neue erstellen.
Und Lang- bzw. Kurzlebigkeit wird nicht über die Zeit definiert sondern über die Generationen, also wie oft ein Objekt eine Reinigung überlebt hat. Objekte, die die erste Reinigung überleben haben eine gute Chance noch viel länger zu leben, weil sie in den meisten Fällen dann nicht mehr betrachtet werden. Der GC geht nämlich davon aus, dass die meisten Objekte nur sehr kurz existieren und die, die eine Reinigung überleben, sehr lange existieren.Ein Aufruf von GC.Collect() ist dann sinnvoll, wenn man gerade eine Menge Objektreferenzen aufgibt und es gerade nicht so schlimm ist, wenn das Programm für ein paar Sekundenbruchteile nicht reagiert. Ich könnte es mir z.B. bei einem Spiel vorstellen, wenn ein Spiel verlassen wird und man ins Hauptmenü zurückkehrt, dass man dann ne Reinigung durchführt, weil es im Hauptmenü schon mal kurz hängen darf.
-
<OT>
@Optimizer: Schau endlich mal ins NADRW-Forum
</OT>MfG SideWinder
-
Recht interressant:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/dotnetgcbasics.asp
Google gibt auch einiges her.
-
Optimizer schrieb:
Der Thread, in dem der GC läuft, versucht bei günstigen Gelegenheiten Speicherbereinigungen auszuführen - also z.B. dann, wenn das Program gerade auf eine Nutzer-Eingabe wartet.
Das stimmt so nicht. Die Reinigung wird genau dann durchgeführt, wenn kein neues Objekt allokiert werden kann oder wenn du es anforderst.
Hmm, ja, das ist erst mal richtig:
MSDN schrieb:
Tatsächlich wird eine Garbage Collection erst dann eingeleitet, wenn der Bereich von Generation 0 voll ist.
Das ist vermutlich jedoch nur die halbe Wahrheit. Die Garbage Collector Strategien ändern sich praktisch von Version zu Version.
Hier z.B. findet sich folgendes:MSDN schrieb:
When Does a Collection Happen?
When a time allocation is made, the GC checks to see if a collection is needed.
It looks at the size of the collection, the amount of memory remaining, and the sizes
of each generation, and then uses a heuristic to make the decision.Die Details sind leider alle undokumentiert ...
Optimizer schrieb:
Es entsteht auch kein Wettrennen. Während der Reinigung wird der Heap umgeschichtet und deshalb kann kein Thread solange auf Objekte zugreifen oder gar neue erstellen.
Natürlich werden während der Garbage Colection alle anderen Threads angehalten. Mit "Wettrennen" meinte ich, daß das laufende Programm und der GC abwechselnd Objekte erzeugen und zerstören können. Abgesehen davon können auch noch andere, möglicherweise interne, Threads dazu führen, daß die Garbage Collection angestoßen wird.
Optimizer schrieb:
Und Lang- bzw. Kurzlebigkeit wird nicht über die Zeit definiert sondern über die Generationen, also wie oft ein Objekt eine Reinigung überlebt hat.
Von Zeit war nicht die Rede. Die Lebensdauer eines Objektes wird in erster Linie durch die Verweise bestimmt, die das jeweilige Programm auf das Objekt hält. Als Folge davon ordnet der GC die Objekte den verschiedenen Generationen zu.
-
Mit "Wettrennen" meinte ich, daß das laufende Programm und der GC abwechselnd Objekte erzeugen und zerstören können.
Daraus kann ich nicht auf ein Wettrennen schließen, außerdem hast du geschrieben:
Wer ist schneller, der GC mit dem Zerstören oder Du mit dem Neuerstellen?
Was dann schon ziemlich missverständlich war.
Die Lebensdauer eines Objektes wird in erster Linie durch die Verweise bestimmt, die das jeweilige Programm auf das Objekt hält. Als Folge davon ordnet der GC die Objekte den verschiedenen Generationen zu.
Nein das ist so nicht ganz richtig. Jedes Objekt startet in Generation 0 und nach einer Reinigung wird der "Generation-1-Zeiger" (nach der Kompaktierung des Heaps) hinter das letzte noch lebende Objekt gesetzt. dito für Generation 2.
Die Verweise auf das Objekt haben mit den Generationen nichts zu tun, eine Generation ist einfach ein Speicherbereich aus dem Heap, der bei einer Reinigung eben betrachtet wird oder nicht.Mit dem Punkt, wann die Reinigung durchgeführt wird, scheinst du allerdings Recht zu haben. In der Praxis gibt es sicherlich einige schlaue Überlegungen, die viele Faktoren berücksichtigen, um zu einem günstigen Zeitpunkt die Reinigung durchzuführen, da darf man sich nicht so streng an die Theorie halten.
-
Hi,
Optimizer schrieb:
Daraus kann ich nicht auf ein Wettrennen schließen...
hack' doch bitte nicht so auf diesem Wort herum. Das sollte bloß so eine Art didaktischer Kunstgriff sein :).
Optimizer schrieb:
Nein das ist so nicht ganz richtig. Jedes Objekt startet in Generation 0 ...
Ja schon, aber was hat das mit meinem Beitrag zu tun. Das habe ich nicht in Zweifel gezogen. Mir ging es um die Frage nach Ursache und Wirkung - du schreibst:
Optimizer schrieb:
Und Lang- bzw. Kurzlebigkeit wird nicht über die Zeit definiert sondern über die Generationen, also wie oft ein Objekt eine Reinigung überlebt hat.
Das ist so, als würde ich sagen: Es muß wohl Nacht sein, da es dunkel ist. Es kann aber auch sein, daß irgend ein Spaßvogel mir eine Tüte über den Kopf gezogen hat. Die Ursache für die Einordnung der Objekte in die Generationen ist die Lebensdauer des Objektes innerhalb der Applikation ...
Optimizer schrieb:
Die Verweise auf das Objekt haben mit den Generationen nichts zu tun
Das könnte ein Mißverständnis sein. Ich sprach von Verweisen, die das Programm auf die Objekte hält und die sind, wie gerade schon erwähnt, maßgeblich dafür verantwortlich, daß ein Objekt der Generation 0 eine Garbage Collection übersteht und in die nächste Generation verschoben wird. Das ist IMHO unstrittig. Die MSDN bezeichnet solche Objekte häufig als "erreichbare" Objekte.
-
Egal, wir meinen wohl beide das selbe.
-
Na gut.
-
Na gut.