java - 为什么 Java VM 在出现 "Too many open files"错误后无法恢复?

标签 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。

虽然应用程序通常将卸载的类记录到标准输出,但我在“太多打开的文件”错误之前、期间或之后没有看到任何此类日志。

我最初的理论是,当 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

最佳答案

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

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

关于java - 为什么 Java VM 在出现 "Too many open files"错误后无法恢复?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2485424/

相关文章:

JSP 页面中的 javax.el.PropertyNotFoundException

java - 我应该在学 JSP 之前学 Java 吗?

Java - keyTyped 问题

jvm - 某些JVM将ByteCode加载到内存后会做什么?

jvm - java.lang.OutOfMemoryError : requested 16 bytes for CHeapObj-new. 交换空间不足?

java - 使用 Hibernate 生成 Create_Date 和 Update_Date 列

hibernate - 为什么类元空间在 Java 8 中会随着时间的推移而增加?

带有 Tomcat 8.5.8 的 Spring Boot 1.4.2 崩溃,端口已被使用。适用于 Tomcat 8.5.6

web-services - Wso2 文件上传。连接重置

Java CMS 被忽略,取而代之的是 Full GC