Java 当流未显式关闭时,Files.list(Path dir)中是否存在资源泄漏?

Java 当流未显式关闭时,Files.list(Path dir)中是否存在资源泄漏?,java,stream,java-8,Java,Stream,Java 8,我最近编写了一个小应用程序,定期检查目录的内容。过了一会儿,由于打开的文件句柄太多,应用程序崩溃了。经过一些调试,我在以下行中发现了错误: Files.list(path.get(destination)).forEach(path->{ //塞满 }); 然后,我检查了javadoc(我可能早就应该这么做了)中的文件 * <p> The returned stream encapsulates a {@link DirectoryStream}. * If timely disp

我最近编写了一个小应用程序,定期检查目录的内容。过了一会儿,由于打开的文件句柄太多,应用程序崩溃了。经过一些调试,我在以下行中发现了错误:

Files.list(path.get(destination)).forEach(path->{
//塞满
});
然后,我检查了javadoc(我可能早就应该这么做了)中的
文件

* <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's {@link Stream#close close} method is invoked after the stream
* operations are completed
当我用lsof-p检查打开的文件句柄时,我仍然可以看到“/”的打开文件句柄列表越来越长


我现在的问题是:在这种情况下,是否有任何隐藏机制最终应该关闭不再使用的打开文件句柄?或者这些资源实际上从未被处理过,javadoc在谈到“及时处理文件系统资源”时有点委婉吗?

如果关闭流,
Files.list()
会关闭它用来流式处理文件的底层
DirectoryStream
,因此,只要关闭流,就不会有资源泄漏

您可以看到
文件的源代码中关闭
目录流的位置。列表()
如下:

return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false)
                    .onClose(asUncheckedRunnable(ds));
要理解的关键是
Runnable
是使用
Stream::onClose
在流本身关闭时调用的流注册的。该Runnable由一个工厂方法创建,
asUncheckedRunnable
,该方法创建一个
Runnable
,关闭传递给它的资源,将
close()
过程中抛出的任何
IOException
转换为
UncheckedIOException

通过确保
按如下方式关闭,可以安全地确保关闭
目录流

try (Stream<Path> files = Files.list(Paths.get(destination))){
    files.forEach(path -> {
         // Do stuff
    });
}
try(流文件=文件.list(path.get(destination))){
files.forEach(路径->{
//做事
});
}

关于IDE部分:Eclipse基于局部变量(和显式资源分配表达式)执行资源泄漏分析,因此您只需将流提取到局部变量:

Stream<Path> files =Files.list(Paths.get(destination));
files.forEach(path -> {
 // To stuff
});
streamfiles=files.list(path.get(destination));
files.forEach(路径->{
//塞满
});
然后Eclipse会告诉你

资源泄漏:“文件”从未关闭

在幕后,分析工作伴随着一系列异常:

  • 所有可关闭的
    s都需要关闭
  • java.util.stream.stream
    (可关闭)不需要关闭
  • java.nio.file.Files
    中的方法生成的所有流都需要关闭
  • 该策略是在图书馆团队讨论
    是否应为
    自动关闭

    列表文件列表=null时与图书馆团队协调制定的;
    
       List<String> fileList = null;
    
       try (Stream<Path> list = Files.list(Paths.get(path.toString()))) {
       fileList = 
         list.filter(Files::isRegularFile).map(Path::toFile).map(File::getAbsolutePath)
                                    .collect(Collectors.toList());
       } catch (IOException e) {
        logger.error("Error occurred while reading email files: ", e);
      }
    
    try(Stream list=Files.list(path.get(path.toString())){ 文件列表= list.filter(Files::isRegularFile).map(Path::toFile).map(File::getAbsolutePath) .collect(Collectors.toList()); }捕获(IOE异常){ logger.error(“读取电子邮件文件时出错:”,e); }
    没错,如果不关闭流,则文件句柄永远不会关闭。但是,如果进程退出,操作系统将在退出后进行清理。我怀疑他们所说的“及时”可能是指“在过程结束之前”。虽然我觉得你不应该这样使用流不是很直观。此外,IDE似乎不会就潜在的资源泄漏向您发出警告,即使它应该很容易找到。IDE不会发出警告,因为几乎所有的
    都不需要关闭。理想情况下,
    Files.list()
    会有一些注释,比如IDEs可以理解的
    @CloseTheReturnedStream
    。测试代码假设必须通过
    finalize()
    执行自动清理,但现代代码通常使用基于
    幻影引用的清理程序,不是由
    System.runFinalization()
    触发的。因此,即使有自动清理,您的代码也不会检测到它。但是看着,否则你就看不到清洁工了…你救了我一天!在这段代码中,我们到底在哪里关闭流?@Simrankaur,这是一个try_with_资源的示例。无论try块是正常完成还是异常完成,在
    try
    之后括号内声明的变量都将自动关闭。很好,谢谢。虽然这段代码可能会回答这个问题,但最好包含一些上下文,解释它是如何工作的以及何时使用它。从长远来看,只使用代码的答案是没有用的。