为什么在“打开太多文件”错误后Java VM无法恢复?

时间:2010-03-21 01:06:56

标签: java tomcat jvm noclassdeffounderror

在某些众所周知的情况下,我们的应用程序将打开太多套接字(数据库连接)并达到操作系统允许的最大打开文件。我们理解这一点;我们正在解决这个问题并提高限制。

我们无法解释的是,即使在连接数量减少且我们完全在限制范围内之后,我们的部分应用程序仍无法恢复。

在这种情况下,它是在Tomcat下运行的应用程序。

当发生这种情况时,我们首先会看到“打开文件太多”错误:

SEVERE: Socket accept failed
java.net.SocketException: Too many open files
        at java.net.PlainSocketImpl.socketAccept(Native Method)
        at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:390)
        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:61)
        at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:310)
        at java.lang.Thread.run(Thread.java:619)

最终,我们开始在试图打开HTTP连接的应用程序线程中看到NoClassDefFoundError

java.lang.NoClassDefFoundError: org/apache/commons/httpclient/protocol/ControllerThreadSocketFactory
        at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:128)
        at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)
        at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.open(MultiThreadedHttpConnectionManager.java:1349)
       [...]
Caused by: java.lang.ClassNotFoundException: org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1387)
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1233)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
        ... 8 more

当错误的连接消失时,服务器再次开始接受连接,一切似乎都没问题,但我们留下了后一个错误,不断向stderr发送。

虽然应用程序通常会将卸载的类记录到stdout,但我没有在“Too many open files”错误之前,期间或之后看到任何此类日志。

我的初步理论是Hotspot JVM在遇到“打开太多文件”时会卸载看似未使用的类,但如果是这样,它就不会记录这个事实。

编辑:正如Stephen C所示,如果它正在卸载该类,并在第一次重新加载时遇到错误,这可以解释为什么它永远不会恢复。我认为这是一个很好的工作理论。它是否记录在Sun文档中?为什么不记录卸载类通常是卸载类的?

平台详情:

Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) 64-Bit Server VM (build 14.0-b16, mixed mode)

Apache Tomcat Version 6.0.18

2 个答案:

答案 0 :(得分:1)

我认为你重复ClassNotFoundExceptions的原因是由于Socket泄漏问题导致ControllerThreadSocketFactory的第一次尝试类初始化失败。您的代码现在反复执行重新触发类的类初始化的事情,并且它们正在报告原始问题。

如果第一次类初始化失败,那就是它。 JVM不会再尝试这样做。

答案 1 :(得分:0)

使用Weblogic 8.1 / JRockIt R27.2和一堆试图加载资源捆绑的webapps面临同样的问题,然后由于打开文件数量的限制而失败。停止和启动应用程序(即卸载和加载类加载器)使事情再次起作用。