2010-11-29 4 views
2

Ich bin beschäftigt, verwirrt über nicht-deterministische Zerstörung. In einer Antwort auf eine andere question bekam ich den Rat, dass Destruktoren/Finalisierer (von denen ich annehme, sind die gleichen in C#, d. H. Die Funktion namens ~ Klassenname()) sind teuer und nicht erforderlich. Aber mit Blick auf this Beispiel wird ein Destruktor verwendet und aus dem Kommentar klingt, wie es wichtig sein kann. Hat jemand einen Rat bekommen, wie das alles zusammenpasst und sollte ich den Destruktor aus meinem Code entfernen?Verwendung von Destruktor/Finisierer teuer?

Nochmals vielen Dank.

Antwort

3

Sie sollten nur einen Finalizer hinzufügen, wenn Sie absolut haben, um einige Bereinigung an einem bestimmten Punkt auszuführen, ob es explizit durchgeführt wird oder nicht. In solchen Fällen sollten Sie immer eine explizite Möglichkeit haben, die Bereinigung trotzdem zeitnah durchzuführen, und dies sollte die Finalisierung sowieso unterdrücken, damit "gute" Clients keine Leistungseinbußen sehen.

Sie würden normalerweise nur einen Finalizer benötigen, wenn Sie einen direkten Griff zu nicht verwalteten Ressourcen haben - wenn Sie nur einen Verweis auf andere Klasse, die auf der Ressource einen Griff (zB FileStream), dann sollten Sie es auf die verlassen andere Klasse, um einen Finalizer zu haben.

Mit dem Aufkommen von SafeHandle in .NET 2.0, Situationen, in denen es Ihre eigene Finalizerthread schreiben sind very rare indeed wert ist.

Die Leistungseinbußen der Finalizer sind, dass sie Ihre Objekte länger leben lassen, als sie brauchen: Im ersten GC-Zyklus, in dem sie sonst für die Sammlung in Frage kommen, werden sie in die Finalizer-Warteschlange aufgenommen - und sind dort angekommen die nächste Generation genau wie jedes andere Objekt, das einen GC-Zyklus überlebt. Der Finalizer wird dann in einem anderen Thread (irgendwann) laufen und nur dann werden sie berechtigt sein, wirklich gesammelt werden. Anstatt also in der ersten Gen1-Sammlung gesammelt zu werden, leben sie weiter, bis zur nächsten Sammlung, die wesentlich später sein kann.

+0

Ja, schade, dass selbst die Fx4-Version dieses Links SafeHandle nicht erwähnt. –

+0

Eine größere Leistungseinbuße besteht darin, dass alle Objekte , die mit einem finalisierbaren Objekt auf referenziert werden, für eine andere Generation nicht erfassbar sind, ebenso wie Objekte, auf die von diesen verwiesen wird, oder Objekte, auf die sie verweisen usw. Wenn ein Objekt direkt oder indirekt referenziert Objekte, die während der Finalisierung nicht benötigt werden, sollte das Objekt keinen Finalizer haben. Stattdessen sollten die Dinge, die tatsächlich für die Finalisierung benötigt werden, in ihrer eigenen finalisierbaren Klasse eingekapselt werden, und das größere Objekt sollte einen Verweis darauf enthalten. – supercat

1

In der Regel ist die Implementierung eines Destruktors hilfreich, wenn nicht sichergestellt ist, dass der Client-Code alle Ressourcen (Dateiströme, Datenbankverbindungen usw.) ordnungsgemäß schließt. Wenn der Client-Code das nicht schafft, haben Sie Code, der ihn schließt, was besser ist, als die Ressourcen offen zu lassen.

+0

es sei denn, diese Ressourcen haben ihren eigenen Destruktor, wie all Ihre Beispiele tun. –

1

Sie benötigen nur das vollständige Disposable-Muster, wenn Sie direkt mit einer nicht verwalteten Ressource arbeiten. Und dann liegt es an Ihrem aufrufenden Code, sicherzustellen, dass der Destruktor (fast) nie benutzt wird.

Wenn mit verwalteten Ressourcen (= indirekter Besitz von nicht verwalteten Ressourcen) zu tun, der destructor ist nutzlos:

class FileWrapper 
{ 
    private FileStream fs; // managed resource 

    ~FileWrapper() 
    { 
     if (fs != null) 
      fs.Dispose(); // fs is already on the GC finalizer queue 
    } 
} 

Immer wenn eine FileWrapper Aufgabe wird durch die GC gesammelt wird, ist es sicher, dass das fs-Objekt ist in die gleiche Charge. Daher ist der Aufruf von fs.Dispose() nutzlos, indem nur das korrekte Verhalten von FileStream.Dispose() getestet wird.

Der einzige nützliche Destruktor ist hier der in FileStream.

+0

@LukeH: Nein, es ist sicher. Es hätte entsorgt werden können, aber nicht gesammelt. Typ-Sicherheit hält immer noch in einem Destruktor. Und es gibt auch keine Race Condition. –

+1

Ja, du hast Recht, ich denke heute Morgen nicht gerade! – LukeH