Warum Ereignishandler verhindern, dass der Garbage Collector auftritt

8

Ich habe dieses Stück Code

%Vor%

In der Main-Methode meiner Anwendung habe ich

%Vor%

Wenn ich das ausführe, werde ich 0 als Ausgabe haben. Wenn ich Ereignissubskriptionen aus dem Code entferne, erhalte ich das erwartete Ergebnis - das ist 10.

Wenn GC.Collect () aufgerufen wird, wird GC gezwungen, die Garbage Collection zu starten. Da der Abonnent Finalize definiert hat, unterbricht GC die Sammlung, bis finalizequeue leer ist. Dies bedeutet, dass alle Subscription-Instanzen ihre Finalize () aufrufen Methoden (Bitte korrigieren Sie mich, wenn meine Annahmen falsch sind). In der nächsten Zeile wird GC.WaitForPendingFinalizers () aufgerufen, wodurch die Ausführung effektiv ausgesetzt wird, bis die Finalizer-Warteschlange leer ist. Nun, da wir 0 als Ausgabe haben, glaube ich, dass Finalize () nicht aufgerufen wird, was mich glauben lässt, dass GC Abonnenten-Instanzen nicht als gesammelt markiert hat, also Finalizer () Methoden werden nicht aufgerufen.

Ich habe also 2 Fragen

  1. Ist mein Vermutungsrecht und das Ereignis-Abonnement verhindert, dass GC Abonnenten-Instanzen markiert?
  2. Wenn ja, liegt das daran, dass der Verleger einen Verweis auf den Abonnenten enthält? ( Garbage Collector- und Event-Handler )

Meine einzige Vermutung ist, dass, da es zehn Subscriber-Instanzen gibt, die auf dieselbe Publisher-Instanz referenzieren, wenn eine GC-Sammlung stattfindet, dass es andere Verweise auf den Publisher gibt, also nicht gesammelt werden kann, und als Ergebnis: Alle Subskriptionsinstanzen werden zusammen mit dem Publisher in die nächste Generation verschoben, sodass keine Garbage Collection stattfindet und Finalize () nicht zum Zeitpunkt der Ausführung des Befehls Console.WriteLine ( Subscriber.Count.ToString ())

Habe ich recht oder verpasse ich hier etwas?

    
Michael 18.06.2013, 08:54
quelle

2 Antworten

4

Sie identifizieren falsch, was wirklich vor sich geht, eine sehr häufige Falle in C #. Sie müssen das Release-Build Ihres Testprogramms ausführen und es ohne den Debugger ausführen (drücken Sie Strg + F5). Die Art, wie es auf dem Computer Ihres Benutzers ausgeführt wird. Und jetzt merke, dass es völlig egal ist, ob du die Veranstaltung abonnierst oder nicht, du bekommst immer 10.

Das Problem besteht darin, dass das Objekt publisher bei Verwendung eines Debuggers nicht erfasst wird. Ich erklärte den Grund dafür im Detail in dieser Antwort .

Erweitern Sie etwas, Sie haben hier zirkuläre Referenzen. Die Subscriber-Objekte verweisen auf das Publisher-Objekt. Und das Publisher-Objekt enthält Verweise auf die Subscriber-Objekte. Zirkuläre Referenzen sind nicht ausreichend, um Objekte am Leben zu erhalten. Und zum Glück wäre die Müllsammlung nicht sehr effektiv, wenn das der Fall wäre. Das Publisher-Objekt muss an anderer Stelle referenziert werden, um am Leben zu bleiben, die lokale Variable ist nicht gut genug.

    
Hans Passant 18.06.2013, 13:21
quelle
3

Die Antwort auf beide Fragen lautet Ja.

    
Henrik 18.06.2013 08:57
quelle