打开的文件过多:打开了多less个,它们是什么,以及打开多less个JVM

我在Java中得到这个exception:

java.io.FileNotFoundException: (Too many open files) 

我正在寻找方法来消除这个问题。

这个错误显然表明JVM已经分配了太多的句柄,底层操作系统不会让它有更多的。 要么是因为不正确的closures连接/stream而导致泄漏。

这个过程不停地运行几天,最终抛出exception。 它在正常运行的12-14天之后重复发生。

你怎么打这个? 有没有办法在JVM中获取分配的句柄列表,或者当它达到一定数量时跟踪? 我很乐意让他们印刷,看看它是如何增长和什么时候。 我不能使用分析器,因为它是一个生产系统,在开发过程中难以重现。 任何build议?

我正在监视自由堆栈大小,并在接近-Xmx中指定总数的1%时发出“警报”。 我也知道,如果我的线程数超过500,那么肯定会失去一些东西。 现在, 有没有办法知道我的JVM从操作系统分配了太多的句柄 ,并且不会让它们回来,例如套接字,打开的文件等等。如果我知道,我就知道在哪里看什么时候。

你没有说你正在运行哪个操作系统,但是如果你在Linux上运行,你可以使用lsof命令

 lsof -p <pid of jvm> 

这将列出由JVM打开的所有文件。 或者,如果您在Windows上运行,则可以使用Process Explorer来显示所有进程的所有打开的文件。

这样做有望使您能够缩小哪些代码保持文件打开状态。

由于你在Linux上,我build议你检查/ proc-Filesystem。 在proc里面,你会发现一个包含你的进程PID文件夹的文件夹calld'fd'。 如果你的进程ID是1234,path是

 /proc/1234/fd 

在该文件夹中,您将find指向所有打开的文件的链接(执行'ls -l')。 通常情况下,你可以通过文件名告诉哪个库/代码可能打开,而不是closures文件。

您可以通过将以下内容添加到/etc/security/limits.conf来更改打开文件的限制:

 * soft nofile 2048 # Set the limit according to your needs * hard nofile 2048 

然后你可以在shell上使用sysctl -p重新加载configuration。 检查这篇文章 。

为了完整起见,您可以使用以下命令validation打开文件的当前限制: ulimit -n

所以,完整的答案(我结合了@phisch和@bramp的答案)。 如果你想检查所有的进程,你应该使用sudo 。 此外它是很好的结果保存到文件 – LSF是不便宜的+此文件可能是有用的进一步调查。

 sudo lsof > lsof.log 

显示坏人:

 cat lsof.log | awk '{ print $2 " " $1; }' | sort -rn | uniq -c | sort -rn | head -5 2687 114970 java 131 127992 nginx 109 128005 nginx 105 127994 nginx 103 128019 nginx 

将文件描述符的列表保存到文件中:

 sudo ls -l /proc/114970/fd > fd.log 

显示顶部打开的文件:

 cat fd | awk '{ print $11 }' | sort -rn | uniq -c | sort -rn | head -n20