Недавно я написал небольшое приложение, которое периодически проверяло содержимое каталога. Через некоторое время приложение разбилось из-за слишком большого количества открытых файлов. После некоторой отладки я обнаружил ошибку в следующей строке:
Files.list(Paths.get(destination)).forEach(path -> {
// To stuff
});
Затем я проверил javadoc (вероятно, должен был сделать это раньше) для Files.list
и нашел:
* <p> The returned stream encapsulates a {@link DirectoryStream}.
* If timely disposal of file system resources is required, the
* {@code try}-with-resources construct should be used to ensure that the
* stream {@link Stream#close close} method is invoked after the stream
* operations are completed
Для меня "своевременное удаление" по-прежнему звучит так, как будто ресурсы будут выпущены в конце концов, прежде чем приложение перестанет работать. Я просмотрел код JDK (1.8.60), но мне не удалось найти подсказки о том, что дескрипторы файлов, открытые Files.list
, снова выпущены.
Затем я создал небольшое приложение, которое явным образом вызывает сборщик мусора после использования Files.list
следующим образом:
while (true) {
Files.list(Paths.get("/")).forEach(path -> {
System.out.println(path);
});
Thread.sleep(5000);
System.gc();
System.runFinalization();
}
Когда я проверил открытые дескрипторы файлов с помощью lsof -p <pid>
, я все равно мог видеть список открытых дескрипторов файлов для "/" дольше и дольше.
Теперь мой вопрос: есть ли скрытый механизм, который должен в конечном итоге закрывать больше не использовать открытые дескрипторы файлов в этом сценарии? Или эти ресурсы на самом деле никогда не расположены, и javadoc немного эвфемистичен, когда говорит о "своевременной утилизации ресурсов файловой системы"?