Сборщик мусора может со временем высвободить ресурсы ОС, благодаря методу finalize()
в классах, которые обертывают ресурсы. Однако освобождение ресурсов ОС в какой-то момент в будущем недостаточно.
В частности, есть две проблемы:
- Вы можете достичь предела ОС задолго до того, как GC сможет запустить. Достижение такого предела не запускает автоматический сборщик мусора, как при исчерпании пространства кучи.
- Даже если вы освободите ресурс ОС, у вас могут остаться буферы уровня приложения, которые не будут очищены.
Например, 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, это не будет проблемой.