2009-09-04 3 views
13

Wir haben in Java keinen Destruktor wie in C++.Was ist der beste Weg, um ein Objekt in Java zu bereinigen?

Q1. Wie sollten wir jedes Objekt in Java aufräumen?

Q2. Gibt es eine Alternative zu einem finally-Block?

Q3. Manchmal müssen wir explizit die Initialisierung/Beendigung eines Codes von Drittanbietern aus unserer Klasse aufrufen, z.

public classs MyClass{ 
    public MyClass(){ 
     ThirdPartyInitialize(); 
    } 

    protected void finalize(){ 
     ThirdPartyTerminate(); 
    } 
} 

Ist dies der richtige Weg?

Antwort

12

Im Allgemeinen können Sie Java-Objekte nicht selbst bereinigen. Der Garbage Collector entscheidet, wann Objekte aufgeräumt werden. Sie können angeben, wenn Sie mit einer Objektreferenz fertig sind, indem Sie sie auf null setzen, aber es ist in der Regel gut genug, wenn Sie den Objektbereich nicht verwenden. In beiden Fällen haben Sie immer noch keine Kontrolle darüber, wann Müll gesammelt wird.

Der Block finally dient zum Ausführen von Aktionen, ob eine Ausnahme von einem try Block ausgelöst wird oder nicht, und ist der beste Ort, um eine Bereinigung durchzuführen. Im Allgemeinen würden Sie nur Nicht-Objekt-Ressourcen wie offene Streams bereinigen.

finalize() kann nicht garantiert aufgerufen werden, da der Garbage Collector nicht garantiert aufgerufen wird, bevor Ihr Programm beendet wird. Es ist nicht wirklich wie ein C++ - Destruktor, weil C++ - Destruktoren immer aufgerufen werden und man sich darauf verlassen kann, dass sie aufgerufen werden. Sie können sich nicht darauf verlassen, dass finalize() aufgerufen wird.

So 1) verwenden finally Blöcke nicht-Objekt Ressourcen freizugeben 2) lassen den Garbage Collector aufzuräumen Objekt-Ressourcen 3) Sie den Garbage Collector andeuten können, dass Sie mit einem Objekt gemacht werden, indem man es null wenn es Einstellung wird in einer lang laufenden Methode verwendet.

0

Das finalize wird ähnlich einem Destruktor verwendet, aber wenn Sie den try ... finally Block für Ressourcen verwenden, können Sie eine Ressource öffnen und im finally Block die Ressource schließen.

Der finally-Block wird immer aufgerufen, wenn der Block entweder normal oder durch eine Ausnahme ausgelöst wird.

Finalisieren ist riskant für die Ressourcenverwaltung, da Sie nicht wissen, wann es aufgerufen wird, und wenn es ein Objekt schließt, das ebenfalls finalisiert wurde, kann es eine Weile dauern.

Der final Block ist der bessere Ansatz.

+0

würde ich * nicht * sagen, dass finalize() ist ähnlich wie bei einem destructor. Der Rest Ihres Textes ist in Ordnung, aber er widerspricht weitgehend dieser ersten Aussage. Sie wissen nie, wann finalize() aufgerufen wird. Im Gegensatz zu einem C++ - Destruktor, der aufgerufen wird, wenn ein Objekt den Gültigkeitsbereich verlässt oder gelöscht wird. –

+0

Wenn ein Objekt als Garbage Collection erfasst wird, wird der Finalizer aufgerufen. Es ist jedoch keine Idee, wann der Garbage Collector gesammelt wird. Daher wird der Finalizer möglicherweise nicht rechtzeitig aufgerufen. –

5

Sie könnten auch ein shutdown hook zu Ihrem Programm hinzufügen, wenn Ihr Programm ist auch heruntergefahren:

//add shutdown hook 
Runtime.getRuntime().addShutdownHook(new Thread() { 
    public void run() { 
     ThirdPartyTerminate(); 
    } 
}); 
1

A1. Wenn Sie ein Objekt nicht initialisieren müssen, dann Dispose pattern is the way to go.

A2. Aus Sicht der Ressourcenverwaltung gibt es keine. Es sollte jedoch beachtet werden, dass ein finally-Block kein deterministisches Ressourcenmanagement ist.

A3. Ja, es ist der richtige Weg.

2

Die beste Möglichkeit, nach Objekten zu bereinigen, besteht darin, das Objekt einfach fallen zu lassen.

Schließlich können Blöcke mit dem Execute Around Idiom abstrahiert werden.

Finalisierer sollten vermieden werden. Sie werden wahrscheinlich nicht sofort angerufen werden. Das Aufräumen sollte trotzdem passieren. Sie sind relativ langsam. Vielleicht möchten Sie einen als Sicherheitsnetzwerk hinzufügen, wenn Sie einen Ressourcenwrapper auf niedriger Ebene schreiben (z. B. für ein Dateihandle), wenn die Leistung nicht kritisch ist.

+0

Gibt es eine Beziehung zwischen Leistung und schließlich blockieren? – pankajt

+0

Ich bin mir nicht sicher, was du meinst. Wenn Sie die Ressource nicht sofort freigeben, haben Sie potentielle Probleme (und nicht nur die Leistung). Wenn Sie keine Ausnahme auslösen, dann macht es bei jeder vernünftigen Ausnahme-Implementierung wenig Unterschied, ob es einen try-Block gibt oder nicht (dies unterscheidet sich von den meisten C++ - Implementierungen). Wenn der Inhalt des finally-Blocks langsam ist, kann es sich lohnen, zu einem Pool zurückzukehren (selbst wenn der "Pool" die Ressource nur in einem separaten Thread freigibt). –

1

Sie können Objekte bereinigen, indem Sie Verweise darauf entfernen, wenn Sie sie nicht mehr benötigen. Sie müssen es nicht explizit tun. Bei einer expliziten Bereinigung müsste der Verweis auf null gesetzt werden, um dem Garbage Collector einen Hinweis zu geben, dass das Objekt erfasst werden kann. Dieser Hinweis funktioniert aufgrund von internen Referenzzählungen für jedes Objekt, die intern gepflegt werden. Zum Beispiel


C a = new C(); //create an object of class C and assign it to 'a' 
a = new C(); //create another object of class C and assign it to 'a'. The older object is no longer referred to. It is now eligible for GC. 

Es gibt bessere Alternativen() je nach finalisieren, wie viel finalize(), um Ihre Situation zu helfen.

Oft empfiehlt es sich, eine Methode wie close() oder disposeResources() in der API bereitzustellen, die es dem Aufrufer ermöglicht, die API bei der Bereinigung zu unterstützen. Zum Beispiel die java.sql.Connection class does this. Dies ist besser als die Methode finalize(), da die JVM die finalize() -Methode aufruft. Oft wird die finalize() -Methode von einem Thread mit niedriger Priorität in der JVM ausgeführt, was zu merkwürdigen Fehlern führt.

Im Falle der Connection-Klasse erweist sich das Warten auf die Fertigstellung der JVM in vielen Anwendungen als kostspielig, da eine Datenbank nur so viele Verbindungen gleichzeitig aufnehmen kann. Daher rufen die meisten Programmierer close() explizit für ein Connection-Objekt auf.

In Ihrem Fall, sollte es in etwas ähnliches (und in diesem Zusammenhang wird der finally-Block immer laufen garantiert) übersetzen


try 
{ 
ThirdPartyInitialize(); 
// use third party component in this try block 
} 
finally 
{ 
ThirdPartyTerminate(); 
} 

Dies ist ähnlich der, wie der Connection-Klasse auch in den meisten verwendet wird, Situationen.

-1

Ihre Objekte in Java müssen wirklich nie "aufgeräumt" werden, GC funktioniert einfach. Fast jedes Mal, wenn ich someObject = null im Code gesehen habe, war es jemand, der nicht wusste, was er tat. Es gibt einen theoretischen Fall dafür, aber es ist wirklich ein Randfall und in der Regel besser auf andere Weise behandelt wie der kürzlich hinzugefügte Versuch mit Ressource.

Wenn Sie eine externe Ressource haben, die bereinigt werden muss, wenn ein Objekt nicht mehr verwendet wird, ist das eine andere Sache.

Es gibt "Referenz" -Klassen, die einen speziellen Referenztyp für Ihre Klasse enthalten - es wird nicht die Garbage Collection stoppen, sondern Sie benachrichtigen, wenn die Klasse Garbage Collected gesammelt wurde (durch einen Callback, wenn Sie möchten). Nachschlagen WeakReference, PhantomReference usw.

Diese sind zuverlässig und arbeiten in einer viel deterministischeren Weise als eine tatsächliche "finalisieren" -Methode, weil der Rückruf außerhalb Ihrer Klasse ist, so dass Sie am Ende keine Methode in einigen vorgelöschten oder halbgelöschten ausführen Zustand und die Probleme, die verursachen könnten.

+0

Dies ist keine Antwort auf die obige Frage, da Sie im Wesentlichen sagen, dass sie ihre Objekte nicht aufräumen sollen. Es gibt viele Instanzen (insbesondere bei Verwendung eines Ereignisbusses und Thread-Variablen), bei denen Objekte für diese Systemtypen bereinigt und nicht registriert werden müssen. Wenn Sie sehr einfache Pojos verwenden, dann müssen Sie ja nicht viel tun. Jede remote komplexe Aufgabe muss jedoch auf undichte Objekte untersucht werden, da dies die Hauptursache für Probleme in der heutigen Community ist. – dsutherland

+0

Tatsächlich erfordern viele Java-Objekte, dass Sie eine Bereinigungsmethode für sie aufrufen. 'Obj.open (...); Obj.close(); ' – iPherian

1

Zwei Syntax Zucker Optionen:

1) Es gibt eine @Cleanup Anmerkung in Lombok, dass meist ähnelt C++ Destruktoren (more):

@Cleanup 
ResourceClass resource = new ResourceClass(); 

2) Es ist auch try-with-resources Aussage. Zum Beispiel:

try (BufferedReader br = new BufferedReader(new FileReader(path))) { 
    System.out.println(br.readLine()); 
} 
Verwandte Themen