Somewhere I read that it\'s unnecessary to close it by yourself, just leave it, JVM will help you do this. Is it true?
Assume I need to fetch data from file with
Yes, In some point it's true, JVM will help release the file descriptor when GC in some time with invoking finalize
method(you can try to verify it by System.gc()
).
And also totally agree we need to explicitly close InputStream
when we don't need this and release the file descriptor.
but if your application don't frequently operate on file descriptors(file, network io), do we need to care this too? after all, there is finalize
method.
Yes it's a good practice to close
it, explicitly release it.
and for OP's problem is very like Java's: how to safely close the Stream
by Files.lines
. In Java, we can use the try with resources handle this. But Scala not support this, maybe you can try with try ... finally
to handle this, like:
val reader = Source.fromFile("build.sbt").bufferedReader()
try {
reader.lines().forEach(line => {
...
})
} finally {
reader.close()
}
Somewhere I read that it's unnecessary to close it by yourself, just leave it, JVM will help you do this. Is it true?
It is partly true.
If you open a file, use it and then drop the file or stream handle (or whatever you want to call it), AND the GC finds it, THEN the GC will queue the file handle object for finalization. When the finalization occurs the file handler's finalize()
method will release the resources; i.e. the file descriptor.
However, it is a bad idea to rely on the GC to do this.
Put these four things together, and an application can easily run out of file descriptors before the GC gets around to collecting and closing the abandoned file handles. If that happens, you are liable to get exceptions on operations that open files, directories, sockets, etcetera.
Here's an example you can run (on Linux / UNIX) to see this happening:
import java.io.FileInputStream;
public class Test {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 100000; i++) {
new FileInputStream("/etc/motd");
}
}
}
$ javac Test.java
$ java Test
Exception in thread "main" java.io.FileNotFoundException: /etc/motd (Too many open files)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at Test.main(Test.java:6)
1 - A typical GC only runs when the heap (or part of the heap) reaches a given threshold of "fullness". If an application doesn't allocate many objects, it can take a long time for the threshold to be reached.
2 - Modern JVMs use generational garbage collectors which collect different parts of the heap at different rates.