当流未明确关闭时,Files.list(Path dir)中的资源泄漏? [英] Resource leak in Files.list(Path dir) when stream is not explicitly closed?

查看:171
本文介绍了当流未明确关闭时,Files.list(Path dir)中的资源泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆