2015-10-22 15 views
7

Ich würde gerne wissen, wann ein Stream schließt, wenn es nicht manuell geschlossen wird. Damit meine ich, wird der Strom geschlossen, wenn der Umfang seiner Referenz nicht mehr ist?Wann schließt ein Stream, wenn er nicht manuell geschlossen wird?

Betrachten Sie das folgende Beispielszenario.

Class A{ 
InputStream in; 
OutputStream out; 
A(){ 
    // Initialize and create the streams. 
} 
... 
} 
Class B{ 
public void myMethod(){ 
A a = new A(); 
System.out.println("End of my method.") 
} 
... 
} 

Hier einmal bin ich mit dem Strom gemacht, ich myMethod() aber das Programm, das der Prozess wiederum geht nicht mit anderen Operationen beendet und bin zu verlassen.

Ich habe die Streams nicht geschlossen. Wird es automatisch geschlossen, sobald der Umfang der Referenz auf die Klasse A endet? (dh. Wenn myMethod() endet)? Kümmert sich GC darum? Außerdem lese ich, dass die Ströme geschlossen werden, sobald der Prozess endet und das System alle Ressourcen freigibt, die für andere Prozesse für es gehalten werden. Wie können wir überprüfen, ob der Stream geöffnet ist oder nicht? Gibt es Linux-Befehle oder -Optionen von Java, um das zu überprüfen?

Jede Hilfe wird geschätzt!

+0

In der Regel sollten Sie immer alle Streams (und Closeables im Allgemeinen) in einem 'finally' Block (oder Try-with-resources) schließen –

+0

An diesem Punkt lehne ich mich in meinem Stuhl zurück, und ich versuche es Ich erinnere mich an alle Java-Streams, die ich geöffnet habe, und ich nahm an, dass sie automatisch außerhalb des Bereichs geschlossen wurden. Seit 15 Jahren. Dann stehe ich auf und schreie "C++ Ich liebe dich so hart". – Chameleon

Antwort

10

Ich glaube nicht, dass die JVM-Spezifikation irgendeine Garantie dafür gibt. Sie sollten wirklich finally diese Ressourcen schließen.

Wenn der Prozess beendet wird, gibt das Betriebssystem alle damit verbundenen Ressourcen frei (einschließlich Speicher, Dateihandles und Netzwerk-Sockets).

Es gibt OS-Funktionen, die über geöffnete Dateien und Streams prüfen, z. B. lsof.

+1

Ja, ich schließe es in "endlich" Block, aber fragte aus Neugier. Aber denken Sie nicht, GC sollte so konfiguriert sein, dass Sie sich auch darum kümmern? Sobald der Gültigkeitsbereich einer Referenz endet, sollten alle von ihm zusammen mit dem Speicher referenzierten Datenströme gesammelt werden. Ist es nicht? –

+0

Ja, GC wird irgendwann passieren. Es ist jedoch nicht garantiert, dass es zeitgemäß ist, und es ist nicht vollständig garantiert, dass der Finalizer ausgeführt wird (wodurch der Stream geschlossen wird). Die Haltung ist, dass der Entwickler sich darum kümmern soll. – Thilo

0

Das ist eine schlechte Programmierpraxis, ein Fehler vom Programmierer. Abhängig von der zugrunde liegenden Datenquelle wird es möglicherweise nie geschlossen und Sie können Lecks haben. Sie MÜSSEN jede Ressource schließen, wenn Sie damit fertig sind, in einem finally Block, oder versuchen Sie es mit Ressourcen, wenn Java 7 oder höher, um sicherzustellen, dass es geschlossen ist, selbst wenn eine Ausnahme ausgelöst wird.

InputStream in; 
OutputStream out; 
try { 
    // Do your stuff with the streams 
} finally { 
    if (in != null) { 
     in.close(); 
    } 
    if (out != null) { 
     out.close(); 
    } 
} 
4

Wenn Sie clossing es nicht manuell dann alle nicht verwalteten Ressourcen werden freigegeben, wenn der Prozess termiantes, jedoch ist es nicht zu empfehlen oder eine bewährte Methode. Du solltest deinen Stream immer schließen, wenn du damit fertig bist.

Ein besserer und vorgeschlagene Weg, um den Strom zu verwalten, ist mit Ressource-Option wie folgt zu verwenden versuchen:

try (InputStream input = new FileInputStream(...); 
    Reader reader = new InputStreamReader(input, ...)) { 
    ... 
} 

ich nicht die Ströme geschlossen habe. Wird es automatisch geschlossen, wenn der Gültigkeitsbereich der Referenz auf Klasse A endet?

Nein, es wird nicht automatisch geschlossen.

Eine gute Referenz folgen ist:

Better Resource Management with Java SE 7: Beyond Syntactic Sugar

2

Im Fall FileInputStream gibt es eine finalize() Methode, die Ressourcen freizugeben, wenn der Strom Müll gesammelt wird.

Nicht, dass Sie sich darauf verlassen können oder sollten. Es ist genau das, was FileInputStream tut.SocketInputStream auf der anderen Seite überschreibt finalize(), um explizit nichts zu tun, unter Berufung auf Socket, um die Ressourcen zu schließen (und Socket hat keine finalize() Methode).

0

Mit Java 7 können Sie eine oder mehrere "Ressourcen" in der try-Anweisung erstellen. Ein "Ressourcen" ist etwas, das die Schnittstelle java.lang.AutoCloseable implementiert. Diese Ressource wird automatisch geschlossen und das Ende des try-Blocks wird beendet.

Sie this und java doc für weitere Informationen

Privat static void printFileJava7 aussehen kann() throws IOException {

try(FileInputStream input = new FileInputStream("file.txt")) { 

    int data = input.read(); 
    while(data != -1){ 
     System.out.print((char) data); 
     data = input.read(); 
    } 
} 

}

Wenn der try-Block der Fileinputstream beendet wird automatisch geschlossen. Dies ist möglich, weil FileInputStream die Java-Schnittstelle java.lang.AutoCloseable implementiert. Alle Klassen, die diese Schnittstelle implementieren, können innerhalb des Try-with-Resources-Konstrukts verwendet werden.

1

Es wird nicht garantiert, dass die Ressourcen geschlossen werden, solange die JVM läuft. Ihre vorgeschlagene Implementierung ist ziemlich gefährlich.

Was ich vorschlagen würde. Machen Sie die Klasse A zu einem geschlossenen und verwenden Sie die tryResourceClose-Anweisung von Java. Das Beispiel ist hier. https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

Nachdem Sie den Try-Block verlassen haben, haben Sie die Möglichkeit, Ihre Ressourcen zu schließen.

Der Stream selbst weiß normalerweise nicht, ob es offen ist oder nicht. Ihre eigene Klasse A kann jedoch verfolgen, ob die Streams geschlossen wurden oder nicht.