繁体   English   中英

Files.walkFileTree使用自定义FileVisitor泄漏目录描述符

[英]Files.walkFileTree leaking directory descriptors with custom FileVisitor

我在应用中遇到了一个奇怪的错误。 我已经通过解决方法解决了它,但我仍然很好奇为什么会发生此错误。

下面给出了一个自定义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 这不应该是垃圾收集吗?

Files#list()文档中

返回的流封装了DirectoryStream 如果需要及时处理文件系统资源,则应使用try-with-resources构造来确保在流操作完成之后调用流的close方法。

最终,将对流进行垃圾收集,但不会立即进行。 因此,在这种情况下,您必须自己进行管理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM