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

Java Files.walkFileTree使用自定义FileVisitor泄漏目录描述符,java,file,Java,File,我在我的应用程序中遇到了一个奇怪的错误。我已经通过一个变通方法解决了这个问题,但我仍然很好奇为什么会发生这个错误 下面给出了一个自定义FileVisitor的示例,该自定义FileVisitor正在删除它遍历的空目录。如果目录不是空的,并且它仍然遍历这些目录,那么它将泄漏目录描述符。如果我将lsof与应用程序的PID一起使用,它将显示一组描述符,指向相同的几个目录,即它遍历的目录 private String getOldestFile() { fileVisitor.clearOlde

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

下面给出了一个自定义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;
    }
}
编辑2:我已设法将问题隔离到以下行:
文件.list(dir).collect(Collectors.toList()).size()==0
。这不应该被垃圾收集吗?

来自:

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

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

来自:

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


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

这里没有打开任何文件的代码,那么为什么要创建文件描述符呢?你能发一段lsof的输出吗?@Thomas是的,我也不懂那部分。如果我对getOldestFile()进行注释;管线,根本没有泄漏。发布了lsof输出snippet.Ah,所以它不是为文件打开文件描述符,而是为目录打开文件描述符。你可以在你的问题中纠正这个问题。@Thomas,那是我的错。现在更正它。不过,问题仍然存在。顺便说一句,使用
文件.list(dir).collect(Collectors.toList()).size()是在浪费内存和CPU资源。创建列表只是为了找到其大小。那么
Files.list(dir).count()
呢?这里没有打开任何文件的代码,为什么要创建文件描述符?你能发一段lsof的输出吗?@Thomas是的,我也不懂那部分。如果我对getOldestFile()进行注释;管线,根本没有泄漏。发布了lsof输出snippet.Ah,所以它不是为文件打开文件描述符,而是为目录打开文件描述符。你可以在你的问题中纠正这个问题。@Thomas,那是我的错。现在更正它。不过,问题仍然存在。顺便说一句,使用
文件.list(dir).collect(Collectors.toList()).size()是在浪费内存和CPU资源。创建列表只是为了找到其大小。那么
Files.list(dir).count()
呢?使用close()垃圾回收应该回收的垃圾。非常感谢。使用close()垃圾会按应有的方式收集垃圾。谢谢。
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