Does JVM automatically closes files?

前端 未结 2 442
眼角桃花
眼角桃花 2021-01-16 04:59

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

2条回答
  •  夕颜
    夕颜 (楼主)
    2021-01-16 06:03

    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.

    • If a file handle is reachable, then the GC won't finalize it.
    • You have of way of knowing when the GC is going to run next1.
    • And when the GC runs, it won't necessarily collect all of the garbage2.
    • And objects that are queued for finalization don't get actually finalized until after the GC finishes. (See @Holger's comment)

    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.(FileInputStream.java:138)
        at java.io.FileInputStream.(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.

提交回复
热议问题