Laden...

Circular Dependencies und GC

Erstellt von Traumzauberbaum vor 17 Jahren Letzter Beitrag vor 17 Jahren 2.287 Views
T
Traumzauberbaum Themenstarter:in
512 Beiträge seit 2006
vor 17 Jahren
Circular Dependencies und GC

Ich habe ein Hauptobjekt, dass von vielen Nebenobjekten verwendet wird.
Eigentlich reicht es aus, dass die Nebenobjekte das Hauptobjekt kennen um ihre Funktion zu erfüllen.
Dieses Hauptobjekt hat aber eine Eigenschaft, die bei Änderung alle Nebenobjekte funktionsunfähig macht.

Und damit hätte ich dann den Kreis gebaut. Das Hauptobjekt müsste sich irgendwie eine Liste der Nebenobjekte merken und diese dann benachrichtigen, dass sie nutzlos sind.

Mein Problem dabei ist der GC.
Dadurch, dass das Hauptobjekt die Nebenobjekte irgendwo gespeichert hat, werden diese nicht mehr vom GC gesammelt. Ich hätte quasi trotz GC ne Möglichkeit für Memory Leaks gefunden...
Ich könnte höchstens mit IDisposable die Verantwortung für das Memory Leak an den Benutzer der Nebenobjekte übertragen. Der Anwender muss dann dafür sorgen, dass Dispose auch aufgerufen wird, wenn er speicher freigeben will. Das läuft mir aber irgendwie gegen den Sinn einer Umgebung mit GC. Dispose sollte ja eher dazu da sein Resourcen zu einem kontrollierten Zeitpunkt freizugeben, und nicht um überhaupt Resourcen freizugeben.

WeakReferences wären auch keine Lösung die mir gefallen würde. Entweder ich hab dann den MemoryLeak eben mit WeakReferences statt mit den Nebenobjekten, oder ich müsste irgendwie regelmäßig durch die Liste gehen und schauen ob ich eine WeakReference loswerden kann. Und die Regelmäßigkeit könnte ich nur garantieren, indem ich alle Befehle das ausführen lasse (schlecht) oder einen zusätzlichen Thread beauftrage das zu tun (schlechter).

Eine Alternative wäre eine Art Identifikator (z.B. GUID), der sich immer ändert wenn die Eigenschaft sich ändert. Wenn der Identifikator in den Nebenobjekten nicht mehr mit dem des Hauptobjekts übereinstimmt, wissen diese dann dass sie entwertet wurden. Es interessiert mich ja auch nicht wie sich die Eigenschaft geändert hat, sondern nur dass er sich geändert hat. Der Overhead wäre auf jeden Fall vernachlässigbar.

Was meint ihr denn dazu? Es geht hier auch nicht hauptsächlich um Performance, sondern um ein gutes Design ohne Löcher.

e.f.q.

Aus Falschem folgt Beliebiges

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Traumzauberbaum,

Eigentlich reicht es aus, dass die Nebenobjekte das Hauptobjekt kennen um ihre Funktion zu erfüllen.

Die Nebenobjekte sollte das Haupobjekt nicht/nie kennen! Normalerweise entkoppelt man dass durch Events. Reicht dir das, oder sollte/muss ich den Rest deiner Frage auch noch lesen?

herbivore

T
Traumzauberbaum Themenstarter:in
512 Beiträge seit 2006
vor 17 Jahren

Wie soll das denn durch Events entkoppelt werden?

Ich könnte alle Funktionen die vom Hauptobjekt benötigt werden als Delegate übergeben, aber das ändert ja am Problem nichts.

Oder ich könnte die Nebenobjekte in ein Event vom Hauptobjekt registrieren lassen, aber auch das ändert am Problem nichts, die Nebenobjekte landen trotzdem nicht beim GC.

Der Grund warum die alle ein gemeinsames Objekt kennen ist Synchronisation mehrerer Threads. Das Hauptobjekt war vorher da und hat den Zugriff auf bestimmte Resourcen threadsicher gemacht. Die Nebenobjekte sind neu und enthalten kompilierten Code der den Zugriff auf die Resourcen performanter macht. Nur wenn sich etwas am Hauptobjekt ändert, funktioniert dieser Code nicht mehr. Das ist nicht weiter tragisch, es passiert selten und es wäre kein Problem das dann zu handhaben. Aber ich muss es handhaben können, und dazu muss ich es merken.
Ein statisches Objekt zur Synchronisation ist auch keine Lösung, denn es sollen jeweils nur Gruppen untereinander synchronisiert sein und nicht immer alle.

e.f.q.

Aus Falschem folgt Beliebiges

B
119 Beiträge seit 2005
vor 17 Jahren

Hallo,

falls deine Nebenobjekte derzeit nur vom Hauptobjekt referenziert werden, würde ich einfach das Hauptobjekt beim Eintreten dieser Eigenschaft wegwerfen und neu erstellen, wodurch der Kreis sozusagen bereits mit einem Bein im Grab steht.

grüße

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Traumzauberbaum,

zyklische Abhängigkeiten hindern den GC übrigens nicht am Aufräumen.

herbivore

T
Traumzauberbaum Themenstarter:in
512 Beiträge seit 2006
vor 17 Jahren

Ja das ist mir schon klar. Ich will ja auch nur die Nebenobjekte vom GC sammeln lassen, das Hauptobjekt ist sehr langlebig, um nicht zu sagen es wird mit Programmstart instanziert und beim Programmende beerdigt.

Vieleicht stelle ich mir das auch einfach zu umständlich vor. Vieleicht sollte ich einfach den Zugriff auf die Liste der Nebenobjekte nach außen hin zulassen. Dann ist man einfach selbst verantwortlich sein Objekt dort zu deaktivieren, wenn man es loswerden will. Und falls man das nicht tut ist es immerhin kein Leak, man kommt noch von außen ran. Ein Memory Leak zeichnet sich ja dadurch aus, dass das Objekt im Speicher (bei OOP) nicht mehr zugreifbar ist.

e.f.q.

Aus Falschem folgt Beliebiges

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Traumzauberbaum,

Dieses Hauptobjekt hat aber eine Eigenschaft, die bei Änderung alle Nebenobjekte funktionsunfähig macht.

dann musst du doch nur in der Methode alle Referenzen auf die Nebenobjekte wegwerfen.

herbivore

T
Traumzauberbaum Themenstarter:in
512 Beiträge seit 2006
vor 17 Jahren

Die Nebenobjekte können aber auch einfach so mal nicht mehr gebraucht werden, weil sie ihre Funktion erfüllt haben. Und da würde dann erst gewartet werden, bis die Methode ausgelöst wird, bevor der GC sich die holen kann, weil ja im Hauptobjekt noch Referenzen darauf existieren. Es ist ja eigentlich sogar eher die Ausnahme, dass sich etwas so ändert, dass ich die Nebenobjekte abknipsen muss.

Wie gesagt, die einzige Möglichkeit die ich bei diesem Ansatz sehe ist, die Verantwortung dem Benutzer des Objekts zu übergeben. Wenn er es nicht abmeldet wird es eventuell erst viel später bis garnicht gesammelt.

Die andere Variante wäre eben eine Id mitzuführen und zu Vergleichen und die Verantwortung zum deaktivieren direkt beim Nebenobjekt lassen, statt das Hauptobjekt überhaupt erst damit zu belasten.

Und ich hab mich eigentlich gefragt ob ich vieleicht damit völlig auf dem Holzweg bin, ob es für das Problem vieleicht eine Standardlösung gibt, und wenn nichts davon welche Lösung ihr bevorzugen würdet 😁

e.f.q.

Aus Falschem folgt Beliebiges