我已经阅读到该文件是非托管资源,垃圾收集器不会处理该文件。
如果您不关闭文件,我敢肯定,如果没有任何引用,则对该文件的引用将被垃圾回收。那么到底什么保持开放?是在操作系统级别上吗?就像SQL连接一样,我知道操作系统会保持TCP端口打开,并且最终可能会用完端口。但是,如果有文件,打开的是什么?
答案 0 :(得分:4)
由于包装资源的类中的finalize()
方法,垃圾收集器最终可以释放OS资源。但是,将来在某个时候释放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内存的最大大小。