当流未明确关闭时,Files.list(Path dir)中的资源泄漏? [英] Resource leak in Files.list(Path dir) when stream is not explicitly closed?
问题描述
我最近写了一个小应用程序,定期检查目录的内容。过了一会儿,应用程序因为打开文件句柄太多而崩溃。经过一些调试后,我发现以下行中的错误:
I recently wrote a small app that periodically checked the content of a directory. After a while, the app crashed because of too many open file handles. After some debugging, I found the error in the following line:
Files.list(Paths.get(destination)).forEach(path -> {
// To stuff
});
然后我检查了javadoc(我可能应该早点完成) Files.list
并找到:
I then checked the javadoc (I probably should have done that earlier) for Files.list
and found:
* <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
对我来说,及时处理在应用程序退出之前,仍然听起来资源最终会被释放。我查看了JDK(1.8.60)代码,但是我无法找到有关 Files.list
再次发布的文件句柄的任何提示。
To me, "timely disposal" still sounds like the resources are going to be released eventually, before the app quits. I looked through the JDK (1.8.60) code but I wasn't able to find any hint about the file handles opened by Files.list
being released again.
然后我创建了一个小应用程序,在使用 Files.list
后显式调用垃圾收集器:
I then created a small app that explicitly calls the garbage collector after using Files.list
like this:
while (true) {
Files.list(Paths.get("/")).forEach(path -> {
System.out.println(path);
});
Thread.sleep(5000);
System.gc();
System.runFinalization();
}
当我用 lsof检查打开的文件句柄时 - p< pid>
我仍然可以看到/的打开文件句柄列表越来越长。
When I checked the open file handles with lsof -p <pid>
I could still see the list of open file handles for "/" getting longer and longer.
我现在的问题是:在这种情况下,是否有任何隐藏的机制最终应该关闭不再使用的打开文件句柄?或者这些资源实际上从未被处理过,并且在谈论及时处理文件系统资源时,javadoc有点委婉吗?
My question now is: Is there any hidden mechanism that should eventually close no longer used open file handles in this scenario? Or are these resources in fact never disposed and the javadoc is a bit euphemistic when talking about "timely disposal of file system resources"?
推荐答案
如果你关闭Stream, Files.list()
会关闭它用于流式传输文件的底层 DirectoryStream
,所以只要你关闭Stream就不会有资源泄漏。
If you close the Stream, Files.list()
does close the underlying DirectoryStream
it uses to stream the files, so there should be no resource leak as long as you close the Stream.
你可以看到 DirectoryStream
的位置在 Files.list()
的源代码中关闭:
You can see where the DirectoryStream
is closed in the source code for Files.list()
here:
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false)
.onClose(asUncheckedRunnable(ds));
要理解的关键是 Runnable
使用 Stream :: onClose
在Stream中注册,当流本身关闭时调用。 Runnable是由工厂方法 asUncheckedRunnable
创建的,它创建一个 Runnable
,用于关闭传入其中的资源,转换任何 IOException
在 close()
期间抛出到 UncheckedIOException
The key thing to understand is that a Runnable
is registered with the Stream using Stream::onClose
that is called when the stream itself is closed. That Runnable is created by a factory method, asUncheckedRunnable
that creates a Runnable
that closes the resource passed into it, translating any IOException
thrown during the close()
to an UncheckedIOException
通过确保 Stream $ c,您可以放心地确保
DirectoryStream
已关闭$ c>关闭如下:
You can safely assure that the DirectoryStream
is closed by ensuring the Stream
is closed like this:
try (Stream<Path> files = Files.list(Paths.get(destination))){
files.forEach(path -> {
// Do stuff
});
}
这篇关于当流未明确关闭时,Files.list(Path dir)中的资源泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!