Java web应用在执行一段时间之后出现了这么个问题
java.net.SocketException: Too many open files at java.net.PlainSocketImpl.socketAccept(Native Method) at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384 ) at java.net.ServerSocket.implAccept(ServerSocket.java:453 ) at java.net.ServerSocket.accept(ServerSocket.java:421 ) at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:60 ) at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:216 )
用ulimit -a看看Linux 打开文件限制
[admin @test ~]# ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 360448 max locked memory (kbytes, -l) 32 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 10240 cpu time (seconds, -t) unlimited max user processes (-u) 360448 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
用lsof -p [进程ID] 可以看到某ID的打开文件状况。进程ID可能用 ps -ef|grep java列出
[admin @test ~]# lsof -p 1940 COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME java 1940 admin cwd DIR 0 , 68 4096 385090717 /admin/apache-tomcat- 7.0 . 39 /bin java 1940 admin rtd DIR 0 , 68 4096 384141801 / java 1940 admin txt REG 0 , 68 47308 385122308 /admin/jdk1. 6 .0_13/jre/bin/java java 1940 admin mem REG 202 , 3 385122339 /admin/jdk1. 6 .0_13/jre/lib/i386/client/libjvm.so (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385122308 /admin/jdk1. 6 .0_13/jre/bin/java (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385122425 /admin/jdk1. 6 .0_13/jre/lib/i386/client/classes.jsa (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385122426 /admin/jdk1. 6 .0_13/jre/lib/charsets.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 384959153 /lib/libresolv- 2.12 .so (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 384959143 /lib/libnss_dns- 2.12 .so (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385122355 /admin/jdk1. 6 .0_13/jre/lib/i386/libnio.so (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385122354 /admin/jdk1. 6 .0_13/jre/lib/i386/libnet.so (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385122325 /admin/jdk1. 6 .0_13/jre/lib/ext/sunjce_provider.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385122326 /admin/jdk1. 6 .0_13/jre/lib/ext/sunpkcs11.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385122392 /admin/jdk1. 6 .0_13/jre/lib/jce.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385122405 /admin/jdk1. 6 .0_13/jre/lib/resources.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385122391 /admin/jdk1. 6 .0_13/jre/lib/jsse.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385090820 /admin/apache-tomcat- 7.0 . 39 /lib/tomcat-dbcp.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385090824 /admin/apache-tomcat- 7.0 . 39 /lib/tomcat-jdbc.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385090821 /admin/apache-tomcat- 7.0 . 39 /lib/tomcat-i18n-es.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385090816 /admin/apache-tomcat- 7.0 . 39 /lib/jsp-api.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385090817 /admin/apache-tomcat- 7.0 . 39 /lib/servlet-api.jar (path dev= 0 , 68 ) java 1940 admin mem REG 202 , 3 385090813 /admin/apache-tomcat- 7.0 . 39 /lib/el-api.jar (path dev= 0 , 68 )
通过以上命令,我们可以看到open files 的最大数为1024 那么我们可以通过一下命令修改该参数的最大值 2. ulimit -n 4096 [root@test security]# ulimit -n 4096 [root@test security]# ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited file size (blocks, -f) unlimited max locked memory (kbytes, -l) unlimited max memory size (kbytes, -m) unlimited open files (-n) 4096 pipe size (512 bytes, -p) 8 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 7168 virtual memory (kbytes, -v) unlimited
这样我们就修改了系统在同一时间打开文件资源的最大数,基本解决以上问题。
以上部分是查找网络上的解决方法。设置了之后段时间内有作用。
后来仔细想来,问题还是要从根本上解决,于是把以前的代码由认真地看了一遍。终于找到了,罪魁祸首。
在读取文件时,有一些使用的BufferedReader 没有关闭 。导致文件一直处于打开状态。造成资源的严重浪费。
修改之后的简单代码如下:
public
void
test(){ BufferedReader reader
=
null
;
try
{ reader
=
读取文件; String line
=
""
;
while
( ( ine
=
reader.readLine())
!=
null
){ 其他操作 } }
catch
(IOException e){ System.out.println(e); }
finally
{
if
(reader
!=
null
){
try
{ reader.close(); }
catch
(IOException e) { e.printStackTrace(); } } } }
**********************************************************************************************************************************************
因为Socket没有释放,以致文件句柄用完了.如果用HttpClient去调用的, HttpClient本身存在这个问题, 解决方式就是加个httpHeader, 使用HttpClient如下:
client = new HttpClient(); client.getParams().setBooleanParameter("http.protocol.expect-continue" , false ); HttpMethod httpMethod = ...; httpMethod.addRequestHeader("Connection" , "close" ); client.executeMethod(httpMethod);
client = new HttpClient(); client.getParams().setBooleanParameter("http.protocol.expect-continue" , false ); HttpMethod httpMethod = ...; httpMethod.addRequestHeader("Connection" , "close" ); client.executeMethod(httpMethod);
, 其它的API应该也可以加这两个值.
用unlimit放大操作系统最大打开文件数的确可以短时间解决 Too many open files的现象,但这不是本质原因。
本质原因肯定能够是你的程序中没有及时close掉文件(在linux/unix中Socket也是文件)。否则只有在上千的绝对同时并发时,才可能出现Too many open files错误。