2014-04-06 7 views
9

Ich glaube, offene Streams verursachen Speicherverlust in Java (mindestens Java 1.6 und früher hatte dieses Problem).Verursachen nicht geschlossene Streams Speicherlecks in Java?

Aber während der Suche (auch hier), fand ich einige Leute damit einverstanden, während andere nicht. Also, wenn ich dieses Programm schreiben:

import java.io.*; 
public class CreatingMemoryLeak { 

    public static void main(String args[]) 
    { 
     String s = "xxxxxxx"; 
     InputStream in = new ByteArrayInputStream(ss.getBytes()); 
     BufferedInputStream bf = new BufferedInputStream(in); 

     try { 
      while(bf.read()>0) 
      { 
       System.out.println("got it"); 
      } 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     System.out.println("Here is a input stream " + s +" causing a memory leak"); 

    } 
} 

und wenn ich nicht schließen den bf Stream explizit, wird es einen Speicherverlust verursachen?

+1

Beachten Sie, dass die Idee von 'close' normalerweise darin besteht, native Ressourcen freizugeben (wie C-Heap-allokierte Daten, die gelöscht werden müssen). Das doc für 'ByteArrayInputStream' [sagt ausdrücklich, dass 'close' keine Auswirkung hat] (http://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayInputStream.html#close%28%29). Ich denke also nicht, dass es ein gutes Beispiel dafür ist, was Sie hier wirklich fragen. – Radiodef

Antwort

4

(at least java 1.6 and earlier did had this problem).

JEDE Version von Java, und JEDE Sprache, hat dieses Problem; Es ist nicht spezifisch für Java.

Wenn Sie ein Eingabe- oder Ausgabehandle erhalten, das Systemressourcen benötigt, müssen Sie sie unabhängig von der Art freigeben.

Java hat Closeable um anzuzeigen, dass die Instanz, die Sie halten können, oder kann nicht, halten Sie die Systemressourcen; aber wenn es passiert, wenn Sie nicht .close() es tun, werden Sie Ressourcen verlieren; So einfach ist das.

Zum Beispiel haben Sie vielleicht eine Methode, die eine InputStream als Argument hat; OK, gut, aber was ist das InputStream? Ist es ein FileInputStream oder ein ByteArrayInputStream, oder noch etwas anderes? Du kannst es nicht wissen. Der erste muss ordnungsgemäß geschlossen werden, aber der zweite muss nicht.

Also was? .close() sie alle sowieso, Sie haben nichts zu verlieren. Willst du wirklich das Risiko eingehen?

Mit Java 6, werden Sie Closer Guava die verwendet werden sollen, da dies der sicherste Weg, um all Ihre Ressourcen zu haben, ist geschlossen (und das JDK bietet kein solches Werkzeug):

final Closer closer = Closer.create(); 

try { 
    final InputStream in = closer.register(openInHere()); 
    final InputStream in2 = closer.register(...); 
    final OutputStream out = closer.register(...); 
    // do work with in, in2, out, other 
} catch (WhateverException e) { 
    // IF WhateverException is not an IOException and you want to rethrow... 
    // throw closer.rethrow(e, WhateverException.class); 
} finally { 
    closer.close(); // always safe 
} 

Mit Java 7, haben Sie versuchen-mit-Ressourcen, die mit allen AutoCloseable Ressourcen arbeiten (die Closeable erweitert):

try (
    final InputStream in = ...; 
    // etc 
) { 
    // work with AutoCloseable resources 
} catch (WhateverException e) { 
    // deal with e, rethrow if necessary 
} 

der wesentliche Unterschied zwischen Closer und versucht-with-Ressourcen ist, dass mit dieser, Ressourcen c sein losgelöst vorcatch während Closer wird sie in finally geschlossen.

Aber wieder: keine Chance. Schließen Sie sie alle.

28

Bei der Verwendung des Begriffs "Speicherleck" in Bezug auf Java ist es wichtig, genau zu sein.

In Java, ein Speicherverlust passiert, wenn Ihr Code eine Referenz dauerhaft enthält, so dass einige Objekt nie Müll gesammelt wird.

Das Schließen eines Streams ist in diesem Sinne kein Speicherleck. Streams mit nativen Ressourcen verfügen über Finalizer. Der GC wird sie schließlich schließen. Wenn Sie nicht auf den nicht geschlossenen Stream verweisen, handelt es sich nicht um ein Leck.

Es gibt jedoch andere Arten von Lecks neben Speicherlecks. Die meisten Betriebssysteme begrenzen die Anzahl der geöffneten Dateien.Wenn Sie Ihre Streams nicht schließen können, kann es sehr lange dauern, bis der GC für Sie geschlossen wird. Das Endergebnis kann sein, dass Sie keine Systemdateideskriptoren mehr haben und Ihr Code eine weitere Datei nicht öffnen kann. Manche Leute nennen dies ein Leck, aber es ist nicht korrekt, es als Speicherleck zu bezeichnen.

+6

+1 - Dies ist ein Ressourcenverlust, kein Speicherleck. –

0

Die Antwort hängt vom Stream ab.

Ein Speicherleck ist einfach eine Situation, in der Sie Dinge behalten, die Sie nicht vorhatten. Dies liegt immer an einem Programmierfehler: Irgendwo hat jemand vergessen, einige Instanzen zu lösen ("loslösen" von allen starken Referenzen). Diese addieren sich im Laufe der Zeit und dann bemerken Sie das "Leck". Ein Cache, der unbegrenzt wächst, ist ein gutes Beispiel.

Ein Stream könnte zum Beispiel einige Daten in einen gemeinsamen Container (normalerweise statisch) wie eine Ressourcensperre, irgendeine Art von Cache, usw., sobald er geöffnet/verwendet wird, platzieren. Und dann räumt es diese Ressource in der close-Methode auf. Wenn Sie diesen letzten Teil überspringen, entsteht ein Speicherleck. In Ihrem Beispiel macht die ByteArrayInputStream.close() Methode nichts, also kein Problem. BufferedInputStream.close() delegiert nur den Aufruf an die umhüllte Klasse, in diesem Fall gibt es also wieder kein Problem.

Komplexere Streams mit Dateien, Netzwerk-Streams können Lecks erzeugen, wenn nicht geschlossen, aber es ist nicht üblich. Ich gehe davon aus, dass der Stream selbst nicht verfügbar ist, aber für die Sammlung verfügbar bleibt. In vielen Situationen kann ein "intelligenter" Strom diese Versehen sogar während seiner eigenen Sammlung beheben und die notwendige Säuberung selbst durchführen (dies bleibt eine anomale Situation, die der Strom eindeutig protokollieren/melden sollte).