Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

abfrage disposed .net objekte

5 views
Skip to first unread message

hans

unread,
May 11, 2010, 4:44:01 PM5/11/10
to
Hallo,

irgendwas habe ich bei .net nicht verstanden: wie weiss ich denn, dass ein
objekt noch nicht aufgeraeumt wurde? Manche habe zumindest ein .IsDisposed
property, andere aber nicht mal das, und dann gibt's nur eine
ObjectDisposedException...


Herfried K. Wagner [MVP]

unread,
May 11, 2010, 6:03:02 PM5/11/10
to
Hallo Hans!

Am 11.05.2010 22:44, schrieb hans:
> irgendwas habe ich bei .net nicht verstanden: wie weiss ich denn, dass ein
> objekt noch nicht aufgeraeumt wurde?

Als Autor des Codes weißt Du ja, ob/wann Du die Methode 'Dispose' eines
Objektes aufrufst. Normalerweise ist es so, daß derjenige Teil des
Codes, der ein Objekt erstellt, auch für dessen Freigabe zuständig ist.

Dies wird auch bei einem 'Using'-Block deutlich, der beim Verlassen
implizit die Methode 'Dispose' des Objektes, das an ihn gebunden ist,
aufruft:

\\\
Using x As New Y()
...
End Using
///

'Dispose'-Aufrufe geschehen sonst, außer bei der Freigabe eines
Objektes, nicht automatisch. Und zum Freigabezeitpunkt besteht von den
aktiven Codezweigen aus ohnedies kein Zugriff mehr auf das Objekt.

--
M S Herfried K. Wagner
M V P <URL:http://dotnet.mvps.org/>
V B <URL:http://dotnet.mvps.org/dotnet/faqs/>

Thomas Scheidegger

unread,
May 11, 2010, 6:31:13 PM5/11/10
to
Hallo Hans

nur zur Sicherheit,

> wie weiss ich denn, dass ein objekt noch nicht aufgeraeumt wurde?

damit könnte eher das Thema 'GC' generell gemeint sein(?),

> Manche habe zumindest ein .IsDisposed

und da handelt es sich um den 'Spezialfall' der IDisposable -Schnittstelle,
wenn es etwa um 'nicht verwaltete Ressourcen' geht.

GC
http://msdn.microsoft.com/de-de/library/cc766760.aspx
http://msdn.microsoft.com/de-de/library/ee787088.aspx
http://msdn.microsoft.com/de-de/library/ms973837.aspx
http://msdn.microsoft.com/de-de/magazine/cc163316.aspx
http://msdn.microsoft.com/de-de/library/hks5e2k6.aspx

IDisposable
http://msdn.microsoft.com/de-de/library/498928w2.aspx
http://msdn.microsoft.com/de-de/magazine/cc163392.aspx
http://msdn.microsoft.com/de-de/library/b1yfkh5e.aspx

--
Thomas Scheidegger - 'NETMaster'
http://dnetmaster.net/

hans

unread,
May 13, 2010, 7:35:01 AM5/13/10
to
Hallo Herfried,

danke fuer das feedback, hier ein paar Details warum das ein Problem ist:
sicher weiss ich, wann ich das Objekt nicht mehr brauche, hier z.B. ein
socket. Beim Verlassen der UI wird es per Close() aufgeraeumt, nur dass ein
client evtl noch eine Meldung schickt und die asynchron spaeter auflaufen kann
...
ClientSocket.BeginReceive(ReceiveData, 0, ReceiveData.Length,
SocketFlags.None, New AsyncCallback(AddressOf ReceiveFromClient),
ClientSocket) ' queue a receive callback
...

Private Sub ReceiveFromClient(ByVal iar As IAsyncResult)
Try
Dim ClientSocket As Socket = CType(iar.AsyncState, Socket)
Dim NumByte As Integer = ClientSocket.EndReceive(iar) ' hier schon
Exception
If NumByte <> 0 Then
If SocketIsDisposed = True Then ' handgestrickte Schutzvariable
Return ' funktioniert aber nicht
End If
Dim receivedData As String =
System.Text.Encoding.ASCII.GetString(ReceiveData, 0, NumByte)
Try
ProcessCommands(ClientSocket, receivedData)
Catch ex As ObjectDisposedException
System.Diagnostics.Debug.Print("Disposed HACK !! ") '
End Try
...

Ich kann (wahrscheinlich) ueberall Try/catch bloecke verstreuen und die
exceptions dann abfangen, aber so richtig sauber ist das ja nicht...Und der
Versuch mit der Schutzvariablen, die ich auf True setze sobald der socket
geschlossen wurde, funktioniert nicht immer, race condition

Hmm, wie gesagt, manche .net Objekte haben diese .IsDisposed() property, die
wohl vom GC gesetzt wird, macht ja auch Sinn. Nur ein
System.Net.Sockets.Socket eben nicht, daher die Frage

Gruss
Hans

> .
>

Thomas Scheidegger

unread,
May 13, 2010, 8:01:00 AM5/13/10
to
> ueberall Try/catch bloecke

so falsch ist das nicht (insbesondere mit Sockets)

> socket ... per Close() aufgeraeumt, nur dass ein client evtl noch


> eine Meldung schickt und die asynchron spaeter auflaufen kann

dazu gibt es bei Sockets im Prinzip den 'Shutdown' Vorgang:
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.shutdown.aspx

> .IsDisposed() property, die wohl vom GC gesetzt wird

nein,
hat hier mit dem GC wenig zu tun, sondern IDisposable
(siehe meine Links)

hans

unread,
May 13, 2010, 8:35:01 AM5/13/10
to
Hallo Thomas,

danke fuer die vielen links, muss ich noch mal genau lesen...mein Problem
(siehe mein Kommentar an Herfried) betrifft sockets, also verwaltete Objekte,
und in den links ist die Rede, dass dispose() das Leben von Objekten (z.B. in
generation2) verkuerzt, also eine Hilfe fuer den gc, was ja ok ist.
Unverstaendlich finde ich nur, dass es Objekte gibt, die ich gar nicht
abfragen kann !?
Als alter C++ freak habe ich schon philosophische Probleme,
Speicherverwaltung aus den Haenden zu geben, wenn ich dann aber nicht mal
fragen kann, ob die Arbeit erledigt wurde...
Es ist ja moeglicherweise eine akademische Frage, aber eigentlich muesste
doch jedes gc verwaltete Objekt eine Abfrage haben, ob es noch ansprechbar
ist, so verstehe ich die .IsDisposed property. Ich erzeuge es, benutze es und
im einfachen (single threaded) Fall weiss ich auch wann ich es nicht mehr
verwende/verwenden kann. Im multi threaded Fall beschliesst der gc irgendwann
das Object frei zu geben und wenn ich nicht per Hand fuer jedes Objekt (!)
und thread safe (!!) mitfuehre wann es nicht mehr zu verwenden ist...
Ufff, viel Aufwand, meine Hoffnung war/ist, dass ich da etwas nicht
gesehen/verstanden habe...

Gruss
hans

"Thomas Scheidegger" wrote:

> .
>

Thomas Scheidegger

unread,
May 13, 2010, 9:24:39 AM5/13/10
to
Hans,

in einer 'optimalen' .NET-Welt würde der GC die Lebensdauer
aller Objekte 'vollautomatisch' verwalten,
da müsstest du gar nichts selber machen.
Nun, bei diesem GC-Konzept ist der Zeitpunkt der Zerstörung 'undefiniert',
der GC läuft irgendwann/gelegentlich ('non-deterministic'),
um Objekte, die nicht mehr länger benötigt (= erreichbar/referenziert)
werden,
zu zerstören.

Einige .NET-Klassen sind nun aber nicht 'rein' managed,
sondern 'kapseln' intern ein unmanaged System/Win32- 'Handle',
so wie eben zB auch ein native Winsock-Handle!
Das Problem nun:
Hier kann es logischerweise sinnvoll/nötig sein, dass dieses Handle zu einem
vom Programmierer bestimmten Zeitpunkt geschlossen wird!
Zwar haben die meisten dieser Klassen folglich eine
explizite Methode zum schliessen [typisch: Close()],
aber bieten daneben typisch auch einen weiteren,
'universelleren' Mechanismus mit dem IDisposable - Interface.

Gerade bei der Socket-Klasse ist der Unterschied der beiden
aber auch recht klar:
ein Close() beendet primär nur die Verbindung (Session)
und schliesst dabei das Winsock-Handle,
dagegen das Dispose() bezeichnet _zusätzlich_ auch,
dass man das _ganze_ Socket-Objekt nicht mehr länger benötigt.

Eine .IsDisposed - Eigenschaft ist technisch
eigentlich irrelevant und scheint mir relativ willkürlich,
ein simpler Merker wenn Dispose schon mal aufgrufen wurde.

Carsten Posingies

unread,
May 14, 2010, 6:02:35 PM5/14/10
to
Hallo Hans,

> Als alter C++ freak habe ich schon philosophische Probleme

Ja, das normal. Das geht vielen so. Aber gewöhne Dich einfach an den
Gedanken, dass der GC aufräumt, wenn es ihm passt, egal, ob Du IDisposable
implementierst oder auch nicht.

Der GC ist, insbesondere in .NET 4, recht defensiv. Das heißt, ein Objekt,
das Du nicht mit voller Absicht in den Trashcan haust, existiert
möglicherweise noch ziemlich lange, aber auch, dass dasselbe Objekt unter
anderen Umständen weg sein kann. Und zwar wirklich weg. Wenn "SomeObject"
schon vom GC ins Nirvana getreten worden ist, latscht ein
"someObject.IsStillAlive"-Accessor in ne Exception, weil "someObject"
bereits null ist und somit die Einsprung-Adresse zu "IsStillAlive" schon mit
sonstigem Code einer ganz anderen Komponente überschrieben worden ist.

In der managed Welt, verlass Dich einfach nicht auf implizite Referenzen.
Besonders nicht, wenn Du WeakRefernces benutzt. Aber auch so nicht. Geh
immer davon aus, dass eine Instanz nicht da ist. Prüfe auf null. Und schau
mal nach Sieberslebens Repair-Komponenten. Das könnte da ein Ansatz für Dich
sein.

Carsten

G�nter Prossliner

unread,
May 17, 2010, 4:24:55 AM5/17/10
to
Hallo Carsten!

Entschuldige bitte, aber Dein Posting ist in vielen Punkten ungenau und auch
falsch.

> Der GC ist, insbesondere in .NET 4, recht defensiv.

AFAIK hat sich der grundlegende Algorithmus (welche Speicher werden also
Root-References angesehen, und die "Nachverfolgung" dieser) seit .NET 1.0
nicht ge�ndert.

> Das hei�t, ein
> Objekt, das Du nicht mit voller Absicht in den Trashcan haust, ...

Wie soll das bitte gehen? In .NET geht eben genau das explizite L�schen von
Objekten (ala c++ 'delete pObject') nicht.

> Wenn "SomeObject" schon vom GC ins Nirvana getreten
> worden ist, latscht ein "someObject.IsStillAlive"-Accessor in ne

> Exception, ...

Von welchem Accessor sprichst Du? Bei WeakReferences gibt es das 'IsAlive'
Property, mehr dazu aber sp�ter.

> weil "someObject" bereits null ist und somit die
> Einsprung-Adresse zu "IsStillAlive" schon mit sonstigem Code einer

> ganz anderen Komponente �berschrieben worden ist.

Bei einer CLR welche sich standardkonform verh�lt ist das nicht m�glich.
Auch eine 'NullReferenceException' ist nicht m�glich, da der GC eben keine
(starken) Referenzen auf 'Null' setzt.

> In der managed Welt, verlass Dich einfach nicht auf implizite
> Referenzen. Besonders nicht, wenn Du WeakRefernces benutzt. Aber auch
> so nicht. Geh immer davon aus, dass eine Instanz nicht da ist.

Wie kannst Du so einen Ratschlag geben? Durch den Algorithmus des GC wirst
Du *niemals* auf eine (starke) Referenz auf eine Objekt halten k�nnen
welches vom GC schon freigegeben wurde, weil eben zumindest diese (direkt
oder indirekt) zugreifbare Referenz eine Collection verhindern w�rde.

Nat�rlich lassen sich auch "Spezialf�lle" konstruieren, wie z.b. die
Zuweisung einer Objektreferenz aus Finalize(), wobei daraus resultierende
auf eine starke Referenz "resurrection" vom Inhalt her ung�ltig (durch Code
in .Finalize() Methoden welcher f�r diesen Objektegraph ggf. schon vorher
aufgerufen wurde), niemals kann aber der Speicher schon freigegeben oder gar
"�berschrieben" worden sein.

> Pr�fe auf null.

Wenn eine Referenz "mal da war", dann wird diese "immer w�ren", es sein
denn:
* diese wird �berschrieben (ggf. von einem anderen Thread d.h. ein
vorliegender Bug w�re dann eine Race-Condition)
* die AppDomain wird entladen
* der Prozess wird beendet

mfg GP


0 new messages