Discussion:
Destruktion-Problem wenn Objekte auf sich gegenseitig verweisen?
(zu alt für eine Antwort)
Markus Sandheide
2004-01-12 14:16:45 UTC
Permalink
Mal eine Frage von jemandem der nur C++ kennt:

Wenn ich das richtig verstehe funktioniert das Zerstören
von Objekten bei C# automatisch sobald kein Pointer auf
das Objekt mehr existiert.

Aber was ist wenn Objekte auf sich gegenseitig verweisen?
Objekt A verweist auf Object B
Objekt B verweist auf Object C
Objekt C verweist auf Object B

Sobald das Object A zerstört wird habe ich keinen
Zugriff mehr auf B und C, diese werden aber auch
nicht zerstört, weil die Pointer ja noch existieren.

Richtig?

Markus Sandheide
Jürgen Beck
2004-01-12 14:39:43 UTC
Permalink
Post by Markus Sandheide
Wenn ich das richtig verstehe funktioniert das Zerstören
von Objekten bei C# automatisch sobald kein Pointer auf
das Objekt mehr existiert.
Aber was ist wenn Objekte auf sich gegenseitig verweisen?
Objekt A verweist auf Object B
Objekt B verweist auf Object C
Objekt C verweist auf Object B
Sobald das Object A zerstört wird habe ich keinen
Zugriff mehr auf B und C, diese werden aber auch
nicht zerstört, weil die Pointer ja noch existieren.
Hallo Markus,

es gibt hierbei eigentlich nur ein Problem. Und zwar wird in ausreichend
vielen .NET-Büchern das Konzept leider nur ungenau erklärt.

Kurz:
Gibt es aus dem Code heraus keine Referenz mehr auf das Objekt, verbleibt es
bei einer Garbage Collection nicht im Speicher. Eine Referenz von einem
anderen Objekt heraus ist irrelevant, wenn dieses nicht ebenfalls vom Code
referenziert wird.

In folgendem Buch wird das übrigens sehr gut erklärt:
http://www.amazon.de/exec/obidos/ASIN/3860636502/qid=1073918357/sr=1-1/ref=sr_1_11_1/028-0223307-6787723
Microsoft .NET Framework Programmierung.
Jeffrey M. Richter
Preis: EUR 49,90
Gebraucht & neu ab EUR 35,00
Gebundene Ausgabe - 489 Seiten - Microsoft Press Deutschland
ISBN: 3860636502

Alles klar? :-)
--
Jürgen Beck
MCSD.NET, MCDBA, MCT
www.Juergen-Beck.de
Markus Sandheide
2004-01-12 19:22:28 UTC
Permalink
Mein Beispiel war:

A->B
B<->C

A wird gelöscht.

Wenn ich die Antworten hier richtig verstehe
ist die Garbage Collection intelligent genug
zu merken, daß B und C sich nur noch gegenseitig
verweisen und löscht beide.

Aber wie soll das gehen wenn z.B.
B in seinem Destruktor auf C zugreift und
C in seinem Destruktor auf B?
Jürgen Beck
2004-01-13 15:46:29 UTC
Permalink
Post by Markus Sandheide
A->B
B<->C
A wird gelöscht.
Wenn ich die Antworten hier richtig verstehe
ist die Garbage Collection intelligent genug
zu merken, daß B und C sich nur noch gegenseitig
verweisen und löscht beide.
Hallo Markus,


fast richtig. :-)

Das Ergebnis (dass beide gelöscht werden) ist richtig.

Der Vorgang zum Herausfinden, welche Objekte gelöscht werden müssen, ist
aber ein anderer.
Es wird _nicht_ herausgefunden, welche Objekte gelöscht werden müssen.
Stattdessen werden bei einer GC alle Objekte zur Löschung vorgesehen und
dann wird herausgefunden, welche Objekte nich aus dem Code heraus
referenziert werden.
Post by Markus Sandheide
Aber wie soll das gehen wenn z.B.
B in seinem Destruktor auf C zugreift und
C in seinem Destruktor auf B?
Es gibt keinen Destruktor mehr.
Stattdessen gibt es nur noch einen Finalizer, der (leider) syntaktisch
genauso aussieht.
Dort dürfen nur nicht verwaltete Objekte zerstört werden.
Auf verwaltete Objekte zuzugreifen, um diese freizugeben, macht hier keinen
Sinn, da diese sowieso automatisch freigegeben werden. Stattdessen sollte
man das Dispose-Designpattern (siehe .NET-Dokumentation) einsetzen, um
explizit Ressourcen freizugeben.

Etwas klarer? :-)
--
Jürgen Beck
MCSD.NET, MCDBA, MCT
www.Juergen-Beck.de
Jürgen Beck
2004-01-13 15:54:46 UTC
Permalink
Post by Jürgen Beck
Der Vorgang zum Herausfinden, welche Objekte gelöscht werden müssen,
ist aber ein anderer.
Es wird _nicht_ herausgefunden, welche Objekte gelöscht werden müssen.
Stattdessen werden bei einer GC alle Objekte zur Löschung vorgesehen
und dann wird herausgefunden, welche Objekte nich aus dem Code heraus
referenziert werden.
Post by Markus Sandheide
Aber wie soll das gehen wenn z.B.
B in seinem Destruktor auf C zugreift und
C in seinem Destruktor auf B?
Es gibt keinen Destruktor mehr.
Stattdessen gibt es nur noch einen Finalizer, der (leider) syntaktisch
genauso aussieht.
Dort dürfen nur nicht verwaltete Objekte zerstört werden.
Auf verwaltete Objekte zuzugreifen, um diese freizugeben, macht hier
keinen Sinn, da diese sowieso automatisch freigegeben werden.
Stattdessen sollte man das Dispose-Designpattern (siehe
.NET-Dokumentation) einsetzen, um explizit Ressourcen freizugeben.
Siehe dazu übrigens auch:
http://blogs.msdn.com/ricom/archive/2003/12/02/40780.aspx
Rico Mariani ist CLR Performance Architect bei Microsoft und sollte wissen
wovon er spricht.

Auszug:
"Almost-rule #2: Never have finalizers
(except on leaf objects which hold a single unmanaged resource and nothing
else)

In C++ it's common to use destructors to release memory. It's tempting to do
that with finalizers but you must not. The GC will collect the memory
associated with the members of a dead object just fine without those members
needing to be nulled. You only need to null the members if you want part of
the state to go away early, while the object is still alive (see above). So
really the only reason to finalize is if you're holding on to an unmanaged
resource (like some kind of operating system handle) and you need to Close
the handle or something like that.

Why is this so important? Well, objects that need to be finalized don't die
right away. When the GC discovers they are dead they are temporarily brought
back to life so that they can get queued up for finalization by the
finalizer thread. Since the object is now alive so is everything that it
points to! So if you were to put a finalizer on all tree nodes in an
application for instance, when you released the root of the tree, no memory
would be reclaimed at first because the root of the tree holds on to
everything else. Yuck! If those tree nodes need to be finalized because they
might hold an unmanaged resource it would be much better* to wrap that
unmanged resource in a object that does nothing else but hold the resource
and let that wrapper object be the finalized thing. Then your tree nodes are
just normal and the only thing that's pending finalization is the one
wrapper object (a leaf), which doesn't keep any other objects alive.

*Note: Whenever I say "it would be much better" that's special
performance-guy-techno-jargon, what I really mean is: "It probably would be
much better but of course you have to measure to know for sure because I can
never predict anything."

Actually, the situation is even worse than I made it out to be above, when
an object has a finalizer it will necessarily survive at least one
collection (because of being brought back to life) which means it might very
well get promoted. If that happens, even the next collect won't reclaim the
memory, you need the next collect for the next bigger generation to reclaim
the memory, and if things are going well the next higher level of collect
will be happening only 1/10th as often, so that could be a long time. All
the more reason to have as little memory as possible tied up in finalizable
objects and all the more reason to use the Dispose pattern whenever possible
so that finalization is not necessary.

Of course if you never have finalizers, you won't have to worry about these
problems."
--
Jürgen Beck
MCSD.NET, MCDBA, MCT
www.Juergen-Beck.de
Torsten Oberprieler
2004-01-14 07:33:45 UTC
Permalink
Post by Jürgen Beck
Der Vorgang zum Herausfinden, welche Objekte gelöscht werden müssen,
ist aber ein anderer.
Es wird _nicht_ herausgefunden, welche Objekte gelöscht werden müssen.
Stattdessen werden bei einer GC alle Objekte zur Löschung vorgesehen
und dann wird herausgefunden, welche Objekte nich aus dem Code heraus
referenziert werden.
Post by Markus Sandheide
Aber wie soll das gehen wenn z.B.
B in seinem Destruktor auf C zugreift und
C in seinem Destruktor auf B?
Hallo NG

Meine Frage: Macht es eigentlich Sinn, Verweise
auf untergeordnete/übergeordnete Objekte auf NULL
zu setzen, um die GC bei der Freigabe der Objekte
zu unterstützen?

Ich setze in "Dispose()" alle Verweise des Objekts auf NULL.
Ich denke, je mehr Verweise auf andere Objekte NULL sind,
umso schneller ist die GC mit der Freigabe-Arbeit fertig.

Stimmt das so? Macht das Sinn?

Gruß Torsten
Thomas Tomiczek [MVP]
2004-01-14 08:37:12 UTC
Permalink
Post by Torsten Oberprieler
Hallo NG
Meine Frage: Macht es eigentlich Sinn, Verweise
auf untergeordnete/übergeordnete Objekte auf NULL
zu setzen, um die GC bei der Freigabe der Objekte
zu unterstützen?
Nein. Das macht keinen Unterschied.

Setze sie trotzdem auf NULL - hiilft deinem Programm Fehler zu finden :-)
Post by Torsten Oberprieler
Ich setze in "Dispose()" alle Verweise des Objekts auf NULL.
Ich denke, je mehr Verweise auf andere Objekte NULL sind,
umso schneller ist die GC mit der Freigabe-Arbeit fertig.
Stimmt das so? Macht das Sinn?
Nein, Ja.,

Wie gesagt - macht sinn, weill dann ein Fehlerhaftes Programm dass dein
Objekt nutzt nne Exception bekommt :-) Hilft bei der Fehlersucht.

Bei einem Mark&Sweep algorythmus macht das ansonsten keinen UNterschied -
ja, der GC ist ein klein wenig schneller. Dafür hast DU den Overhead des auf
null setzens. Das kommt in etwa auf das gleiche.

Aber beim Debuggen hift es ungemein. Ich hab meist auch noch ein Bool drinn
(_Disposed) dass ich dann schnell anschauen kann um zu sehen ob die
NullPointer jetzt ein Fehler meines programms war oder des Objekts.

Thomas Tomiczek
THONA Software & Consulting Ltd.
(Microsoft MVP C#/.NET)
Herfried K. Wagner [MVP]
2004-01-12 15:14:21 UTC
Permalink
Hallo Markus!
Post by Markus Sandheide
Wenn ich das richtig verstehe funktioniert das Zerstören
von Objekten bei C# automatisch sobald kein Pointer auf
das Objekt mehr existiert.
Aber was ist wenn Objekte auf sich gegenseitig verweisen?
Objekt A verweist auf Object B
Objekt B verweist auf Object C
Objekt C verweist auf Object B
Sobald das Object A zerstört wird habe ich keinen
Zugriff mehr auf B und C, diese werden aber auch
nicht zerstört, weil die Pointer ja noch existieren.
Entweder du baust die Referenzen selbst ab (z.B. die von C nach B, dann
die von B nach C usw.) und/oder du schaust dir die Klasse
'WeakReference' an.
--
Herfried K. Wagner [MVP]
<http://www.mvps.org/dotnet>
Jürgen Beck
2004-01-12 17:46:05 UTC
Permalink
Post by Herfried K. Wagner [MVP]
Post by Markus Sandheide
Wenn ich das richtig verstehe funktioniert das Zerstören
von Objekten bei C# automatisch sobald kein Pointer auf
das Objekt mehr existiert.
Aber was ist wenn Objekte auf sich gegenseitig verweisen?
Objekt A verweist auf Object B
Objekt B verweist auf Object C
Objekt C verweist auf Object B
Sobald das Object A zerstört wird habe ich keinen
Zugriff mehr auf B und C, diese werden aber auch
nicht zerstört, weil die Pointer ja noch existieren.
Entweder du baust die Referenzen selbst ab (z.B. die von C nach B,
dann die von B nach C usw.) und/oder du schaust dir die Klasse
'WeakReference' an.
Hallo Herfried,

wie kommst Du denn darauf? Das glaube ich Dir irgendwie nicht, dass Du nicht
weißt, dass mehrere Objekte sich ohne Weiteres in der .NET-Welt gegenseitig
referenzieren dürfenohne die Objektzerstörung zu verhindern wie
beispielsweise in der COM-Welt.

Offenbar hast Du die Frage nicht richtig gelesen oder so? :-)
--
Jürgen Beck
MCSD.NET, MCDBA, MCT
www.Juergen-Beck.de
unknown
2004-01-12 17:49:37 UTC
Permalink
Post by Herfried K. Wagner [MVP]
Entweder du baust die Referenzen selbst ab (z.B. die von C nach B, dann
die von B nach C usw.) und/oder du schaust dir die Klasse
'WeakReference' an.
Sorry, aber das ist so nicht korrekt. ;)
Zirkuläre Referenzen innerhalb von Objektbäumen sind egal sobald es keine
ApplicationRootReference mehr gibt.

d.h. in der beschriebenen Situation A->B<->C werden alle drei Objekte zu
Garbage in dem Moment wo A=null kommt. Da es ab diesem Moment keine
RootReference mehr gibt wird der GC alle 3 Objekte entfernen. Das einzige
was hier unklar bleibt ist die Reihenfolge in der die Objekte entfernt
werden und der Thread.
Im Extremfall kann es vorkommen, dass alle 3 Objekte (sofern sie einen
Finalizer besitzen) von 3 unterschiedlichen Threads zu völlig
unterschiedlichen Zeiten entfernt werden.


Und WeakReference hat mit dem gestellten Problem absolut nichts zu tun.
Der Sinn von WeakReference ist Objekte die viel Speicher verbrauchen aber
leicht neu erstellt werden können so zu markieren, dass der GC diese im
Zweifelsfall entfernt wenn ansonsten zuwenig Speicher da wäre. Hierbei
gelten aber die gleichen Regeln wie oben beschrieben. Sobald die
AppRootRef weg ist ist das Zeug Müll.

Gruss
Peter
--
------ooo---OOO---ooo------

Peter Koen - www.kema.at
MCAD MCDBA MCT
CAI/RS CASE/RS IAT

------ooo---OOO---ooo------
Jürgen Beck
2004-01-12 18:00:18 UTC
Permalink
Post by unknown
d.h. in der beschriebenen Situation A->B<->C werden alle drei Objekte
zu Garbage in dem Moment wo A=null kommt. Da es ab diesem Moment keine
RootReference mehr gibt wird der GC alle 3 Objekte entfernen. Das
einzige was hier unklar bleibt ist die Reihenfolge in der die Objekte
entfernt werden und der Thread.
Im Extremfall kann es vorkommen, dass alle 3 Objekte (sofern sie einen
Finalizer besitzen) von 3 unterschiedlichen Threads zu völlig
unterschiedlichen Zeiten entfernt werden.
Hallo Peter,

jupp, dass nennt sich auch "Nichtdeterministische Finalisierung"

Wie gesagt, für diejenigen, die sich für die Innereien von .NET
interessieren, sei das Buch "Microsoft .NET Framework Programmierung" von
Jeffrey M. Richter empfohlen.

:-)
--
Jürgen Beck
MCSD.NET, MCDBA, MCT
www.Juergen-Beck.de
unknown
2004-01-13 03:25:53 UTC
Permalink
Wie gesagt, fr diejenigen, die sich fr die Innereien von .NET
interessieren, sei das Buch "Microsoft .NET Framework Programmierung" von
Jeffrey M. Richter empfohlen.
Ich bevorzuge ein anderes, das mit wesentlich besser gefallen hat. Ist aber
derzeit leider kurzfristig nicht erhältlich:

Simon Robinson, WROX Press, Advanced .NET Programming

Wird aber angeblich demnext neu aufgelegt.

lG
Peter
--
------ooo---OOO---ooo------

Peter Koen - www.kema.at
MCAD MCDBA MCT
CAI/RS CASE/RS IAT

------ooo---OOO---ooo------
Herfried K. Wagner [MVP]
2004-01-12 22:17:09 UTC
Permalink
Hallo Peter!
Post by unknown
Post by Herfried K. Wagner [MVP]
Entweder du baust die Referenzen selbst ab (z.B. die von C nach B, dann
die von B nach C usw.) und/oder du schaust dir die Klasse
'WeakReference' an.
Sorry, aber das ist so nicht korrekt. ;)
Ja, sorry... Ich habe die 3 Zeilen über meiner Antwort überlesen, in
denen der OP beschreibt, dass er die Referenz auf A abbaut :-(.
--
Herfried K. Wagner [MVP]
<http://www.mvps.org/dotnet>
Markus Sandheide
2004-01-13 07:03:08 UTC
Permalink
Post by unknown
d.h. in der beschriebenen Situation A->B<->C werden alle drei Objekte zu
Garbage in dem Moment wo A=null kommt. Da es ab diesem Moment keine
RootReference mehr gibt wird der GC alle 3 Objekte entfernen.
Aber wie soll das gehen wenn z.B. B in seinem Destruktor auf C zugreift
und C in seinem Destruktor auf B? Das ist doch möglich, aber dann kann
die Garbage Collection die Objekte nicht mehr löschen! Wenn B zuerst
gelöscht wird, ist beim Löschen von C dessen Destruktor nicht
mehr ausführbar und umgekehrt.

Oder sehe ich da was falsch?
Joachim Fuchs
2004-01-13 08:45:30 UTC
Permalink
Hallo Markus,
Post by Markus Sandheide
Aber wie soll das gehen wenn z.B. B in seinem Destruktor auf C zugreift
und C in seinem Destruktor auf B? Das ist doch möglich, aber dann kann
die Garbage Collection die Objekte nicht mehr löschen! Wenn B zuerst
gelöscht wird, ist beim Löschen von C dessen Destruktor nicht
mehr ausführbar und umgekehrt.
Destruktoren sind böse und destruktiv (wie der Name schon sagt) und
sollten daher in .NET überhaupt nicht verwendet werden. Es gibt auch
keine sinnvolle Anwendung hierfür. Da man zum Zeitpunkt der
Finalisierung sich auf nahezu nichts verlassen kann, kann man im
Destruktor auch nichts sinnvolles mehr tun. Unter .NET sind Destruktoren
schlichtweg überflüssig.

Gruß
Joachim
--
http://www.fuechse-online.de
http://vbnet.codebooks.de/
Jürgen Beck
2004-01-13 15:53:09 UTC
Permalink
Post by Joachim Fuchs
Post by Markus Sandheide
Aber wie soll das gehen wenn z.B. B in seinem Destruktor auf C
zugreift und C in seinem Destruktor auf B? Das ist doch möglich,
aber dann kann die Garbage Collection die Objekte nicht mehr
löschen! Wenn B zuerst gelöscht wird, ist beim Löschen von C dessen
Destruktor nicht
mehr ausführbar und umgekehrt.
Destruktoren sind böse und destruktiv (wie der Name schon sagt) und
sollten daher in .NET überhaupt nicht verwendet werden. Es gibt auch
keine sinnvolle Anwendung hierfür. Da man zum Zeitpunkt der
Finalisierung sich auf nahezu nichts verlassen kann, kann man im
Destruktor auch nichts sinnvolles mehr tun. Unter .NET sind
Destruktoren schlichtweg überflüssig.
Hallo Joachim,

fast richtig.

Destruktoren gibt es nicht mehr, stattdessen gibt es Finalizer.
Finalizer sind beispielsweise dazu da, um nichtverwaltete Ressourcen
aufzuräumen.

:-)

Siehe dazu übrigens auch:
http://blogs.msdn.com/ricom/archive/2003/12/02/40780.aspx
Rico Mariani ist CLR Performance Architect bei Microsoft und sollte wissen
wovon er spricht.
--
Jürgen Beck
MCSD.NET, MCDBA, MCT
www.Juergen-Beck.de
Joachim Fuchs
2004-01-13 17:25:31 UTC
Permalink
Hallo Jürgen,
Post by Jürgen Beck
fast richtig.
Destruktoren gibt es nicht mehr, stattdessen gibt es Finalizer.
Finalizer sind beispielsweise dazu da, um nichtverwaltete Ressourcen
aufzuräumen.
:-)
ob die nun Destruktoren oder Finalizer heißen, ist bei MS selbst auch
nie so ganz klar. Finalisierer klingt auch nicht positiver als
Destruktor, mehr nach "finalem Rettungsschuss".

Nichtverwaltete Ressourcen räumt man aber üblicherweise in der
Dispose-Überschreibung auf. So macht es MS ja auch in den Form-Klasse
vor. Finalizer (oder wie auch immer) sind daher IMHO völlig überflüssig.

Gruß
Joachim
--
http://www.fuechse-online.de
http://vbnet.codebooks.de/
Jürgen Beck
2004-01-13 18:23:45 UTC
Permalink
Post by Joachim Fuchs
Nichtverwaltete Ressourcen räumt man aber üblicherweise in der
Dispose-Überschreibung auf. So macht es MS ja auch in den Form-Klasse
vor. Finalizer (oder wie auch immer) sind daher IMHO völlig
überflüssig.
Hallo Joachim,

auch nur nur ein _fast_ richtig.

Tatsächlich ist es so, dass im Dispose-Designpattern unverwaltete Ressourcen
aufgeräumt werden:
///
protected virtual void Dispose(bool disposing) {
if(!this.disposed) {
if(disposing) {
Components.Dispose();
}
// Release unmanaged resources. If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
}
disposed = true;
}
\\\

Jedoch gehört zu diesem Pattern ebenfalls ein Finalizer, der die
Dispose-Methode aufruft:
///
~BaseResource() {
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
\\\

Die Begründung ist auch ganz einfach. Wenn der Client vergisst, die
Dispose-Methode aufzurufen, müssen denoch die unverwalteten Ressourcen
aufgeräumt werden, also beispielsweise Speicher freigegeben werden.
--
Jürgen Beck
MCSD.NET, MCDBA, MCT
www.Juergen-Beck.de
Joachim Fuchs
2004-01-13 20:47:58 UTC
Permalink
Hallo Jürgen,
Post by Jürgen Beck
auch nur nur ein _fast_ richtig.
Tatsächlich ist es so, dass im Dispose-Designpattern unverwaltete Ressourcen
///
protected virtual void Dispose(bool disposing) {
if(!this.disposed) {
if(disposing) {
Components.Dispose();
}
// Release unmanaged resources. If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
}
disposed = true;
}
\\\
Jedoch gehört zu diesem Pattern ebenfalls ein Finalizer, der die
///
~BaseResource() {
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
\\\
Die Begründung ist auch ganz einfach. Wenn der Client vergisst, die
Dispose-Methode aufzurufen, müssen denoch die unverwalteten Ressourcen
aufgeräumt werden, also beispielsweise Speicher freigegeben werden.
ja, aber diesen Finalizer programmiert man niemals selbst. Wozu auch,
der ruft ja schon Dispose auf.


Gruß
Joachim
--
http://www.fuechse-online.de
http://vbnet.codebooks.de/
Jürgen Beck
2004-01-13 21:01:58 UTC
Permalink
Post by Joachim Fuchs
Post by Jürgen Beck
Die Begründung ist auch ganz einfach. Wenn der Client vergisst, die
Dispose-Methode aufzurufen, müssen denoch die unverwalteten
Ressourcen aufgeräumt werden, also beispielsweise Speicher
freigegeben werden.
ja, aber diesen Finalizer programmiert man niemals selbst. Wozu auch,
der ruft ja schon Dispose auf.
Hallo Joachim,

was meinst Du damit?

Wenn man ihn nicht selbst in die eigene Klasse schreibt, dann ruft er auch
nicht Dispose auf, was notwendig ist, um Speicher freizugeben, wenn der
Benutzer vergisst, Dispose aufzurufen.

Eventuell sollte man allerdings noch in die Dispose-Methode
GC.SuppressFinalize aufrufen, damit der FInalizerignoriert wird, wenn
tatsächlich Dispose aufgerufen wurde.
--
Jürgen Beck
MCSD.NET, MCDBA, MCT
www.Juergen-Beck.de
Herfried K. Wagner [MVP]
2004-01-13 21:52:06 UTC
Permalink
Hallo Jürgen!
Post by Jürgen Beck
Eventuell sollte man allerdings noch in die Dispose-Methode
GC.SuppressFinalize aufrufen, damit der FInalizerignoriert wird, wenn
tatsächlich Dispose aufgerufen wurde.
Ralf Westphal hat hierzu einen interessanten Artikel in seinem Weblog:

<http://weblogs.asp.net/ralfw/archive/2003/08/08/23185.aspx>
--
Herfried K. Wagner [MVP]
<http://www.mvps.org/dotnet>
Jürgen Beck
2004-01-14 19:26:24 UTC
Permalink
Post by Herfried K. Wagner [MVP]
Post by Jürgen Beck
Eventuell sollte man allerdings noch in die Dispose-Methode
GC.SuppressFinalize aufrufen, damit der FInalizerignoriert wird, wenn
tatsächlich Dispose aufgerufen wurde.
<http://weblogs.asp.net/ralfw/archive/2003/08/08/23185.aspx>
Stimmt, der ist tatsächlich ganz nett, da er doch in einer verständlichen
Sprache das Dispose-Designpattern und dessen Anwendung zusammenfasst.

:-)
--
Jürgen Beck
MCSD.NET, MCDBA, MCT
www.Juergen-Beck.de
unknown
2004-01-13 17:13:45 UTC
Permalink
Post by Markus Sandheide
Aber wie soll das gehen wenn z.B. B in seinem Destruktor auf C zugreift
und C in seinem Destruktor auf B? Das ist doch m”glich, aber dann kann
die Garbage Collection die Objekte nicht mehr l”schen! Wenn B zuerst
gel”scht wird, ist beim L”schen von C dessen Destruktor nicht
mehr ausfhrbar und umgekehrt.
Oder sehe ich da was falsch?
Wenn im Finalizer so ein Konstrukt auftaucht dann gibt es soetwas wie
"Ressurection". Da die Objekte nicht sofort im moment des Abarbeiten des
Finalizers gelöscht werden können diese im Zweifelsfall wiederbelebt
werden.

Das ganze macht die Sache aber nur unnötig kompliziert. Am besten du
verzichtest ganz auf Finalizer, da du die sowieso nur brauchen kannst um
unmanaged Resources freizugeben (bei managed ist das ja irgendwie sinnlos)
und da bist du mit der Implementation und korrekten Nutzung von IDisposable
besser beraten.

Siehe den Post vom Jürgen bezgl. Dispose Pattern

Gruss
Peter
--
------ooo---OOO---ooo------

Peter Koen - www.kema.at
MCAD MCDBA MCT
CAI/RS CASE/RS IAT

------ooo---OOO---ooo------
Herfried K. Wagner [MVP]
2004-01-13 07:29:29 UTC
Permalink
Hallo Peter!
Post by unknown
Und WeakReference hat mit dem gestellten Problem absolut nichts zu tun.
'WeakReference' kann auch in F�llen wie/�hnlich diesen sinnvoll eingesetzt
werden, wenn ich mir die weiteren Posts des OP ansehe.
--
Herfried K. Wagner [MVP]
<http://www.mvps.org/dotnet>
unknown
2004-01-13 17:15:52 UTC
Permalink
Post by unknown
Und WeakReference hat mit dem gestellten Problem absolut nichts zu tun.
'WeakReference' kann auch in F„llen wie/„hnlich diesen sinnvoll
eingesetzt werden, wenn ich mir die weiteren Posts des OP ansehe.
Hallo Herfried,

Ich mag jetza nicht gerade streiten, aber ich muß dir massiv
wiedersprechen.

WeakReference hat mit dem Problem der gegenseitigen Referenzierung absolut
nix am Hut.

Ja, zugegeben, du könntest es nutzen, damit Objekte im Zweifelsfall neu
erstellt werden wenn sie im Finalizer des anderen verwendet werden... Aber
ich glaub nicht, dass das jemand ernsthaft mit einer WeakReference
implementieren möchte.

lG
Peter
--
------ooo---OOO---ooo------

Peter Koen - www.kema.at
MCAD MCDBA MCT
CAI/RS CASE/RS IAT

------ooo---OOO---ooo------
Loading...