Since Dalvik FileInputStream will close itself when it collects garbage (this is also true for OpenJDK / Oracle), it is less common, d I think that file descriptors actually leak. Of course, file descriptors will βleak outβ until the GC works, so depending on your program, this may take some time before they are fixed.
To perform a more permanent leak, you will need to prevent garbage collection by keeping a link to it somewhere in memory.
Here is a quick example that loads a properties file every 1 second and tracks it every time it changes:
public class StreamLeak { public static class Revision { final ZonedDateTime time = ZonedDateTime.now(); final PropertiesFile file; Revision(PropertiesFile file) { this.file = file; } } 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<>();
Due to lazy loading, we save the InputStream in a PropertiesFile, which will be stored whenever we create a new Revision, and since we never close the stream, we will skip the file descriptors here.
Now these open file descriptors will be closed by the OS when the program terminates, but while the program is running, it will continue to leak file descriptors, which can be seen from 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
And if we run GC, we will see that most of them are returned:
$ jcmd 6938 GC.run 6938: Command executed successfully $ lsof | grep pf.properties | wc -l 2
The other two descriptors are those that are stored in versions.
I ran this on my Ubuntu machine, but the result would be similar if you run on Android.