我在我的應用程序中遇到了一個奇怪的錯誤。我已經通過解決方法解決了這個問題,但我仍然很好奇爲什麼會發生這種錯誤。Files.walkFileTree泄漏目錄描述符與自定義FileVisitor
下面給出了一個自定義FileVisitor的示例,該FileVisitor刪除了它所經歷的空目錄。如果這些目錄不是空的,並且它仍然遍歷這些目錄,它將泄漏目錄描述符。如果我在應用程序的PID中使用lsof
,它將顯示一堆描述符,指向相同的幾個目錄,即它走過的那些目錄。
private String getOldestFile() {
fileVisitor.clearOldestFile();
try {
// FIXME: this was throwing FileSystemException: Too many open files after some time running. Leaking file descriptors!!
Files.walkFileTree(Paths.get(csvPath), fileVisitor);
} catch (IOException e) {
e.printStackTrace();
}
return fileVisitor.getOldestFile().toString();
}
class CustomFileVisitor extends SimpleFileVisitor<Path> {
private Path oldestFile = null;
Path getOldestFile() {
return oldestFile;
}
void clearOldestFile() {
oldestFile = null;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (attrs.isDirectory())
return FileVisitResult.CONTINUE;
if (oldestFile == null)
oldestFile = file;
if (oldestFile.compareTo(file) > 0)
oldestFile = file;
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (dir.equals(Paths.get(csvPath)))
return FileVisitResult.CONTINUE;
if (Files.list(dir).collect(Collectors.toList()).size() == 0)
Files.delete(dir); // throws an exception if folder is not empty -> mustn't delete folder with files
return FileVisitResult.CONTINUE;
}
}
CustomFileVisitor僅創建一次,在外類和函數被定期調用等filename = getOldestFile();
編輯:過帳lsof -p {PID}
輸出。在開始時,我發現PID如this。
這就是lsof -p {PID}
輸出的樣子,只有成千上萬行。 「/ home/leon/Development/data /」是Files.walkFileTree的輸入。
java 14965 leon 285r DIR 8,2 4096 1970798 /home/leon/Development/data/2017
java 14965 leon 286r DIR 8,2 4096 1970799 /home/leon/Development/data/2017/10
java 14965 leon 287r DIR 8,2 4096 1970799 /home/leon/Development/data/2017/10
java 14965 leon 288r DIR 8,2 36864 1970800 /home/leon/Development/data/2017/10/17
java 14965 leon 289r DIR 8,2 36864 1970800 /home/leon/Development/data/2017/10/17
java 14965 leon 290r DIR 8,2 4096 1970798 /home/leon/Development/data/2017
java 14965 leon 291r DIR 8,2 4096 1970798 /home/leon/Development/data/2017
java 14965 leon 292r DIR 8,2 4096 1970799 /home/leon/Development/data/2017/10
java 14965 leon 293r DIR 8,2 4096 1970799 /home/leon/Development/data/2017/10
java 14965 leon 294r DIR 8,2 36864 1970800 /home/leon/Development/data/2017/10/17
java 14965 leon 295r DIR 8,2 36864 1970800 /home/leon/Development/data/2017/10/17
編輯2:我已經設法將問題隔離到這一行:Files.list(dir).collect(Collectors.toList()).size() == 0
。這不應該被垃圾收集?
這裏沒有打開任何文件的代碼,爲什麼它會創建文件描述符?你可以發佈'lsof'輸出的片段嗎? – Thomas
@Thomas是的,我也不明白那一部分。如果我評論getOldestFile();行,根本沒有泄漏。發佈lsof輸出片段。 – leonz
啊,所以它不會打開文件的文件描述符,而是打開目錄。你可以在你的問題中糾正這一點。 – Thomas