为什么需要用Java关闭文件打开的连接?

时间:2019-04-09 16:50:59

标签: java file-connection

我已经阅读到该文件是非托管资源,垃圾收集器不会处理该文件。

如果您不关闭文件,我敢肯定,如果没有任何引用,则对该文件的引用将被垃圾回收。那么到底什么保持开放?是在操作系统级别上吗?就像SQL连接一样,我知道操作系统会保持TCP端口打开,并且最终可能会用完端口。但是,如果有文件,打开的是什么?

2 个答案:

答案 0 :(得分:4)

由于包装资源的类中的finalize()方法,垃圾收集器最终可以释放OS资源。但是,将来在某个时候释放OS资源还不够好。

特别是有两个问题:

  1. 您可以在GC有运行机会之前达到操作系统限制。达到此限制不会像堆空间用尽的方式那样触发自动GC。
  2. 即使您释放了OS资源,您仍然可能具有不会刷新的应用程序级缓冲区。

例如,Debian Linux的默认打开文件限制为1024,以防止DoS自身行为异常的程序。考虑一下该程序,每次迭代最好只使用一个FD:

import java.io.*;
class Foo {
  public static void main(String[] args) throws Exception {
    for(int i=0; i<2000; i++) {
      FileInputStream fis = new FileInputStream("Foo.java");
    }
  }
}

运行时会发生以下情况:

$ java Foo
Exception in thread "main" java.io.FileNotFoundException: Foo.java (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 Foo.main(Foo.java:5)

如果您手动关闭了文件,则不会发生。

这是另一个程序的示例,该程序将字符串写入文件,然后将其读回:

import java.io.*;
class Foo {
  static void writeConfig(String s) throws IOException {
    BufferedWriter fw = new BufferedWriter(new FileWriter("config.txt"));
    fw.write(s);
    System.out.println("Successfully wrote config");
  }
  static String readConfig() throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader("config.txt"));
    return reader.readLine();
  }
  public static void main(String[] args) throws Exception {
    writeConfig("Hello World");
    System.gc();  // Futile attempt to rely on the GC
    String input = readConfig();
    System.out.println("The config string is: " + input);
  }
}

这就是您得到的:

$ java Foo
Successfully wrote config
The config string is: null

写入的字符串未写入文件。如果您已关闭BufferedWriter,则不会有问题。

答案 1 :(得分:0)

如果不再有对打开文件的引用,则垃圾收集器肯定会清除内存。但是,只有在收集器运行时才会发生。在此之前,该资源将保留在内存中。

但是,关闭它是一个好主意,因为如果您有很多此类文件处于打开状态,那么如果生成的线程足以打开文件,但您没有关闭它们,则可能会出现内存不足的风险。 -最终在GC启动之前达到JVM内存的最大大小。