java.net.SocketException: Too many open files问题分析及解决方案

来源:互联网 发布:淘宝店铺装修怎么还原 编辑:程序博客网 时间:2024/06/05 17:54

Java web应用在执行一段时间之后出现了这么个问题

[java] view plain copy
  1. java.net.SocketException: Too many open files  
  2.         at java.net.PlainSocketImpl.socketAccept(Native Method)  
  3.         at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384)  
  4.         at java.net.ServerSocket.implAccept(ServerSocket.java:453)  
  5.         at java.net.ServerSocket.accept(ServerSocket.java:421)  
  6.         at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:60)  
  7.         at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:216)  

 用ulimit -a看看Linux打开文件限制

[java] view plain copy
  1. [admin@test ~]# ulimit -a  
  2. core file size          (blocks, -c) 0  
  3. data seg size           (kbytes, -d) unlimited  
  4. scheduling priority             (-e) 0  
  5. file size               (blocks, -f) unlimited  
  6. pending signals                 (-i) 360448  
  7. max locked memory       (kbytes, -l) 32  
  8. max memory size         (kbytes, -m) unlimited  
  9. open files                      (-n) 1024  
  10. pipe size            (512 bytes, -p) 8  
  11. POSIX message queues     (bytes, -q) 819200  
  12. real-time priority              (-r) 0  
  13. stack size              (kbytes, -s) 10240  
  14. cpu time               (seconds, -t) unlimited  
  15. max user processes              (-u) 360448  
  16. virtual memory          (kbytes, -v) unlimited  
  17. file locks                      (-x) unlimited  

 

[java] view plain copy
  1. 用lsof -p [进程ID] 可以看到某ID的打开文件状况。进程ID可能用 ps -ef|grep java列出  

 

[java] view plain copy
  1. [admin@test ~]# lsof -p 1940  
  2. COMMAND  PID USER   FD   TYPE             DEVICE     SIZE      NODE NAME  
  3. java    1940 admin  cwd    DIR               0,68     4096 385090717 /admin/apache-tomcat-7.0.39/bin  
  4. java    1940 admin  rtd    DIR               0,68     4096 384141801 /  
  5. java    1940 admin  txt    REG               0,68    47308 385122308 /admin/jdk1.6.0_13/jre/bin/java  
  6. java    1940 admin  mem    REG              202,3          385122339 /admin/jdk1.6.0_13/jre/lib/i386/client/libjvm.so (path dev=0,68)  
  7. java    1940 admin  mem    REG              202,3          385122308 /admin/jdk1.6.0_13/jre/bin/java (path dev=0,68)  
  8. java    1940 admin  mem    REG              202,3          385122425 /admin/jdk1.6.0_13/jre/lib/i386/client/classes.jsa (path dev=0,68)  
  9. java    1940 admin  mem    REG              202,3          385122426 /admin/jdk1.6.0_13/jre/lib/charsets.jar (path dev=0,68)  
  10. java    1940 admin  mem    REG              202,3          384959153 /lib/libresolv-2.12.so (path dev=0,68)  
  11. java    1940 admin  mem    REG              202,3          384959143 /lib/libnss_dns-2.12.so (path dev=0,68)  
  12. java    1940 admin  mem    REG              202,3          385122355 /admin/jdk1.6.0_13/jre/lib/i386/libnio.so (path dev=0,68)  
  13. java    1940 admin  mem    REG              202,3          385122354 /admin/jdk1.6.0_13/jre/lib/i386/libnet.so (path dev=0,68)  
  14. java    1940 admin  mem    REG              202,3          385122325 /admin/jdk1.6.0_13/jre/lib/ext/sunjce_provider.jar (path dev=0,68)  
  15. java    1940 admin  mem    REG              202,3          385122326 /admin/jdk1.6.0_13/jre/lib/ext/sunpkcs11.jar (path dev=0,68)  
  16. java    1940 admin  mem    REG              202,3          385122392 /admin/jdk1.6.0_13/jre/lib/jce.jar (path dev=0,68)  
  17. java    1940 admin  mem    REG              202,3          385122405 /admin/jdk1.6.0_13/jre/lib/resources.jar (path dev=0,68)  
  18. java    1940 admin  mem    REG              202,3          385122391 /admin/jdk1.6.0_13/jre/lib/jsse.jar (path dev=0,68)  
  19. java    1940 admin  mem    REG              202,3          385090820 /admin/apache-tomcat-7.0.39/lib/tomcat-dbcp.jar (path dev=0,68)  
  20. java    1940 admin  mem    REG              202,3          385090824 /admin/apache-tomcat-7.0.39/lib/tomcat-jdbc.jar (path dev=0,68)  
  21. java    1940 admin  mem    REG              202,3          385090821 /admin/apache-tomcat-7.0.39/lib/tomcat-i18n-es.jar (path dev=0,68)  
  22. java    1940 admin  mem    REG              202,3          385090816 /admin/apache-tomcat-7.0.39/lib/jsp-api.jar (path dev=0,68)  
  23. java    1940 admin  mem    REG              202,3          385090817 /admin/apache-tomcat-7.0.39/lib/servlet-api.jar (path dev=0,68)  
  24. 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如下:
Java代码 
  1. client = new HttpClient();  
  2. client.getParams().setBooleanParameter("http.protocol.expect-continue"false);  
  3. HttpMethod httpMethod = ...;  
  4. httpMethod.addRequestHeader("Connection""close");  
  5. client.executeMethod(httpMethod);  
[java] view plain copy
  1. client = new HttpClient();  
  2.         client.getParams().setBooleanParameter("http.protocol.expect-continue"false);  
  3. HttpMethod httpMethod = ...;  
  4. httpMethod.addRequestHeader("Connection""close");  
  5. client.executeMethod(httpMethod);  
, 其它的API应该也可以加这两个值.

用unlimit放大操作系统最大打开文件数的确可以短时间解决 Too many open files的现象,但这不是本质原因。 
本质原因肯定能够是你的程序中没有及时close掉文件(在linux/unix中Socket也是文件)。否则只有在上千的绝对同时并发时,才可能出现Too many open files错误。
0 0
原创粉丝点击