Da Dalvik Fileinputstream wird close itself when it is garbage collected (dies ist für OpenJDK/Oracle auch wahr) ist weniger verbreitet als man denken würde, um tatsächlich Filedeskriptoren auslaufen. Natürlich werden die Dateideskriptoren solange "durchgesickert", bis der GC läuft. Je nach Programm kann es eine Weile dauern, bis sie wiederhergestellt sind.
Um ein dauerhafteres Leck zu erreichen, müssen Sie verhindern, dass der Datenstrom gesammelt wird, indem Sie irgendwo im Speicher einen Verweis darauf führen.
Hier ist ein kurzes Beispiel, das eine Eigenschaftsdatei alle 1 Sekunden geladen und verfolgt jedes Mal, es hat sich geändert:
public class StreamLeak {
/**
* A revision of the properties.
*/
public static class Revision {
final ZonedDateTime time = ZonedDateTime.now();
final PropertiesFile file;
Revision(PropertiesFile file) {
this.file = file;
}
}
/*
* Container for {@link Properties} that implements lazy loading.
*/
public static class PropertiesFile {
private final InputStream stream;
private Properties properties;
PropertiesFile(InputStream stream) {
this.stream = stream;
}
Properties getProperties() {
if(this.properties == null) {
properties = new Properties();
try {
properties.load(stream);
} catch(IOException e) {
e.printStackTrace();
}
}
return properties;
}
@Override
public boolean equals(Object o) {
if(o instanceof PropertiesFile) {
return ((PropertiesFile)o).getProperties().equals(getProperties());
}
return false;
}
}
public static void main(String[] args) throws IOException, InterruptedException {
URL url = new URL(args[0]);
LinkedList<Revision> revisions = new LinkedList<>();
// Loop indefinitely
while(true) {
// Load the file
PropertiesFile pf = new PropertiesFile(url.openStream());
// See if the file has changed
if(revisions.isEmpty() || !revisions.getLast().file.equals(pf)) {
// Store the new revision
revisions.add(new Revision(pf));
System.out.println(url.toString() + " has changed, total revisions: " + revisions.size());
}
Thread.sleep(1000);
}
}
}
Wegen der trägen Laden halten wir die Input im PropertiesFile die wird beibehalten, wenn wir eine neue Revision erstellen und da wir den Stream nie schließen, werden wir hier Dateideskriptoren verlieren.
nun diese offenen Dateideskriptoren wird durch das OS geschlossen werden, wenn das Programm beendet wird, aber solange das Programm läuft es Filedeskriptoren auslaufen wird auch weiterhin wie lsof unter Verwendung zu sehen:
$ lsof | grep pf.properties | head -n 3
java 6938 raniz 48r REG 252,0 0 262694 /tmp/pf.properties
java 6938 raniz 49r REG 252,0 0 262694 /tmp/pf.properties
java 6938 raniz 50r REG 252,0 0 262694 /tmp/pf.properties
$ lsof | grep pf.properties | wc -l
431
Und wenn wir die GC zu laufen zwingen, können wir sehen, dass die meisten von ihnen zurückgegeben werden:
$ jcmd 6938 GC.run
6938:
Command executed successfully
$ lsof | grep pf.properties | wc -l
2
die verbleibenden zwei Deskriptoren sind die in den Revision s gespeichert diejenigen.
Ich lief dies auf meinem Ubuntu-Rechner, aber die Ausgabe würde ähnlich aussehen, wenn auf Android laufen.
Öffnen Sie einfach eine Reihe von Dateien oder Ports ohne zu schließen? Nach ein paar tausend Fenstern hört auf, sie zu geben. Ähnlich in anderen Betriebssystemen. – Ordous
@Ordous, vielen Dank für Ihre schnelle Antwort. Könnten Sie bitte ein funktionierendes Code-Snippet davon posten – VicJordan