A causa di Dalvik FileInputStream volontà close itself when it is garbage collected (questo vale anche per OpenJDK/Oracle) è meno comune di quanto si potrebbe pensare a perdere realmente descrittori di file. Ovviamente, i descrittori dei file verranno "filtrati" fino a quando il GC non verrà eseguito, quindi a seconda del programma potrebbe essere necessario un po 'di tempo prima che vengano recuperati.
Per realizzare una perdita più permanente, è necessario impedire che il flusso venga raccolto in modo irregolare, conservando un riferimento ad esso nella memoria.
Ecco un breve esempio che carica un file di proprietà ogni 1 secondo e tiene traccia di tutti i tempi è cambiato:
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);
}
}
}
A causa della lazy loading Manteniamo il InputStream nel PropertiesFile che verrà mantenuto ogni volta che creiamo una nuova Revisione e dal momento che non chiudiamo mai il flusso, qui verranno filtrati i descrittori di file.
Ora, questi descrittori di file aperti saranno chiusi dal sistema operativo quando il programma termina, ma fino a quando il programma è in esecuzione continuerà a perdere i descrittori di file come si può vedere, utilizzando lsof:
$ 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
E se si forza il GC per eseguire possiamo vedere che la maggior parte di questi sono tornati:
$ jcmd 6938 GC.run
6938:
Command executed successfully
$ lsof | grep pf.properties | wc -l
2
i restanti due descrittori sono quelli memorizzati nei revisione s.
Ho eseguito questo sulla mia macchina Ubuntu ma l'output sarebbe simile se eseguito su Android.
Basta aprire un gruppo di file o porte senza chiudere? Dopo alcune migliaia di finestre si interrompe dando loro. Simile in altri sistemi operativi. – Ordous
@Ordous, grazie per la tua rapida risposta. Potresti per favore postare un frammento di codice funzionante di esso – VicJordan