22

我有一个 Java 应用程序,它运行得很好(在 Ubuntu 10.04 上)几个小时,直到它遇到“java.net.SocketException:打开的文件太多”。Sender.java 的代码可以在这里找到

是因为我为每个线程创建了一个新实例HttpPutHttpPost?我正在使用 apache-commons HTTPClient 4。

这是异常日志:

java.net.SocketException: Too many open files
    at java.net.Socket.createImpl(Socket.java:414)
    at java.net.Socket.connect(Socket.java:544)
    at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:123)
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:133)
    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:108)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554)
    at com.marketplace.io.Sender.doBasicHttpPost(Sender.java:434)
    at com.marketplace.io.Sender.appVisualExists(Sender.java:223)
    at com.marketplace.io.Sender.addVisualToCollection(Sender.java:350)
    at com.marketplace.service.ImageThread.run(ImageThread.java:136)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:636)
4

5 回答 5

26

“java.net.SocketException: Too many files open”可以在任何 Java Server 应用程序(例如 Tomcat、Weblogic、WebSphere 等)中看到,客户端连接和断开连接频繁。

请注意,套接字连接被视为文件,它们使用文件描述符,这是一种有限的资源。

不同的操作系统对它们可以管理的文件句柄数量有不同的限制。

简而言之,出现此错误是因为客户端经常连接和断开连接。如果您想自己处理它,您有两种选择:

1) 增加每个进程打开的文件句柄或文件描述符的数量。

在基于 UNIX 的操作系统(例如 Ubuntu 或 Solaris)中,您可以使用命令ulimit -a找出每个进程允许打开多少个文件句柄。

$ ulimit -a
core file size        (blocks, -c) unlimited
data seg size         (kbytes, -d) unlimited
file size             (blocks, -f) unlimited
open files                    (-n) 256
pipe size          (512 bytes, -p) 10
stack size            (kbytes, -s) 8192
cpu time             (seconds, -t) unlimited
max user processes            (-u) 2048
virtual memory        (kbytes, -v) unlimited

可以看到,打开文件 (-n) 256,这意味着每个进程只允许打开 256 个文件句柄。如果你的 Java 程序,记住 Tomcat、weblogic 或任何其他应用服务器是 Java 程序并且它们在 JVM 上运行,超过这个限制,它会抛出 java.net.SocketException: Too many files open 错误。

您可以使用 ulimit -n 将此限制更改为更大的数字,例如 4096,但请在 UNIX 系统管理员的建议下进行,如果您有单独的 UNIX 支持团队,最好上报给他们。

2) 减少操作系统中 TIME_WAIT 状态的超时

在基于 UNIX 的系统中,您可以在/proc/sys/net/ipv4/tcp_fin_timeout文件中查看当前配置。

在基于 Windows 的系统中,您可以在 Windows 注册表中看到此信息。您可以按照以下步骤更改 Windows 中的 TCPTIME_WAIT 超时:

1) Open Windows Registry Editor, by typing regedit in run command window
2) Find the key HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\tcpip\Parameters
3) Add a new key value pair TcpTimedWaitDelay asa decimal and set the desired timeout in seconds (60-240)
4) Restart your windows machine.
于 2016-06-03T02:53:11.583 回答
15

On line 438 you get the response as a stream and convert that to a byte array. The InputStream returned by entity.getContent() does not get closed. This could be contributing to the problem. Also, the HttpEntity.consumeContent() is deprecated for related reasons.

于 2011-04-13T22:52:56.883 回答
8

您可能还想检查 linux 最大打开文件限制。此相关链接适用于基于 Java 的定制产品,但它很好地解释了解决问题所需的步骤。

于 2013-04-15T09:26:29.197 回答
1

(解决)

我最近遇到了同样的错误,因为数据库服务器上的 var/log 已满。

#df -h
S.ficheros            Size  Used Avail Use% Montado en

/dev/cciss/c0d0p3     126G  126G    0G 100% /var


#echo "">/var/log/postgresql/postgresql.log

现在,错误消失了!!!

重要:查看登录 postgresql.log 的内容,查看您的 postgresql.conf

再见
@_jpgo

于 2013-10-03T14:11:58.913 回答
0

我通过在 finally 块中关闭连接来解决问题。</p>

public  static String postMethod(String jsonStr,String sendUrl){
    String resultJson = "";
    HttpClient httpClient = new HttpClient();
    PostMethod post = new PostMethod(sendUrl);
    post.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");  
    NameValuePair[] param = { new NameValuePair("message",jsonStr)} ;
    post.setRequestBody(param);
    try {
        httpClient.executeMethod(post);
        resultJson = post.getResponseBodyAsString();
    } catch (HttpException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally{
         post.releaseConnection();
         ((SimpleHttpConnectionManager)httpClient.getHttpConnectionManager()).shutdown();
    }
    return resultJson;
}
于 2016-10-11T07:44:22.473 回答