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
之后括号内声明的变量都将自动关闭。很好,谢谢。虽然这段代码可能会回答这个问题,但最好包含一些上下文,解释它是如何工作的以及何时使用它。从长远来看,只使用代码的答案是没有用的。