我在Java中遇到这个异常:
java.io.FileNotFoundException: (Too many open files)
我正在寻找消除这个问题的方法。
这个错误显然表明JVM分配了太多句柄,而底层操作系统不会让它拥有更多。要么是因为连接/流不正确而导致泄漏。
此过程不间断运行数天并最终抛出异常。在12-14天的正常运行时间后反复发生。
你怎么打这个?有没有办法在JVM中获取已分配句柄的列表或在达到一定数量时跟踪?我喜欢打印它们,看看它是如何生长的。我不能使用分析器,因为它是一个生产系统,并且难以在开发中重现它。有什么建议吗?
当我接近-Xmx中指定总数的1%时,我正在监视空闲堆大小并引发“警报”。我也知道,如果我的线程数达到500以上,那么肯定会失控。现在,有一种方法可以知道我的JVM从操作系统中分配太多句柄并且不会将它们退回,例如插座,打开的文件等。如果我知道,我知道在哪里看,什么时候。
答案 0 :(得分:29)
您没有说明您正在运行哪个操作系统,但如果您在Linux上运行,则可以使用lsof命令
lsof -p <pid of jvm>
这将列出JVM打开的所有文件。或者,如果您在Windows上运行,则可以Process Explorer显示所有进程的所有打开文件。
这样做有望让您缩小代码的哪一部分保持文件打开。
答案 1 :(得分:24)
由于您使用的是Linux,我建议您检查/ proc-Filesystem。在proc中,您将找到一个文件夹,其中包含文件夹calld'fd'的进程的PID。如果您的进程ID为1234,则路径为
/proc/1234/fd
在该文件夹中,您将找到所有已打开文件的链接(执行'ls -l')。通常,您可以通过文件名告诉哪些库/代码可能打开而不关闭文件。
答案 2 :(得分:12)
所以,完整答案(我将@phisch和@bramp的答案结合起来)。
如果要检查所有进程,则应使用sudo
。将结果保存到文件也很不错 - lsof并不便宜+此文件可用于进一步调查。
sudo lsof > lsof.log
显示坏人(来自@ Arun的评论 UPDATE ):
cat lsof.log | awk '{print $1 " " $2 " " $5}' | sort | uniq |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
答案 3 :(得分:10)
您可以通过将以下内容添加到/etc/security/limits.conf
来更改已打开文件的限制:
* soft nofile 2048 # Set the limit according to your needs
* hard nofile 2048
然后,您可以在shell上使用sysctl -p
重新加载配置。检查this article。
为了完整起见,您可以使用以下代码验证打开文件的当前限制:ulimit -n
答案 4 :(得分:1)
如果您使用的是MacOS
sudo launchctl limit maxfiles <hard> <soft>
sudo launchctl limit maxfiles 1024 200000