我在我的应用程序中遇到了一个奇怪的错误。我已经通过解决方法解决了它,但我仍然很好奇为什么会发生这个错误。
下面给出了一个自定义 FileVisitor 的示例,该示例正在删除它遍历的空目录。如果目录不为空,并且它仍然遍历这些目录,它将泄漏目录描述符。如果我lsof
与应用程序的 PID 一起使用,它将显示一堆指向相同目录的描述符,即它遍历的目录。
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 。
这就是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
。这不应该被垃圾收集吗?
返回的流封装了一个
DirectoryStream
. 如果需要及时处理文件系统资源,则应使用 try-with-resources 构造以确保在流操作完成后调用流的 close 方法。
最终,流将被垃圾回收,但不会立即被回收。所以在这种情况下你必须自己管理它。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句