Unter bestimmten Umständen wird unsere Anwendung zu viele Sockets (Datenbankverbindungen) öffnen und die maximal offenen Dateien erreichen, die das Betriebssystem zulässt. Wir verstehen das; Wir beheben das Problem und stossen auch das Limit auf.Warum wird die Java VM nach "zu vielen offenen Dateien" nicht wiederhergestellt?
Was wir nicht erklären können, ist, warum Teile unserer Anwendung nicht wiederhergestellt werden, selbst nachdem die Anzahl der Verbindungen abgeklungen ist und wir innerhalb der Grenzen sind.
In diesem Fall ist es eine Anwendung, die unter Tomcat läuft.
Wenn dies geschieht, wir zum ersten Mal starten „Zu viele Dateien geöffnet“ Fehler sehen:
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)
Schließlich beginnen wir NoClassDefFoundError
s innerhalb eines Anwendungsthread zu sehen, die HTTP-Verbindungen zu öffnen versucht:
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
Wenn die fehlerhaften Verbindungen weggehen, fängt der Server an, Verbindungen wieder anzunehmen, und alles scheint in Ordnung zu sein, aber wir bleiben mit dem letzteren Fehler, der ständig an stderr gespendet wird.
Obwohl die Anwendung in der Regel unloaded Klassen auf stdout protokolliert, sehe ich keine solche Protokolle kurz vor, während oder nach den "zu viele offene Dateien" Fehler.
Meine anfängliche Theorie war, dass die Hotspot-JVM scheinbar unbenutzte Klassen entladen würde, wenn sie auf "Zu viele offene Dateien" stößt, aber wenn ja, protokolliert sie die Tatsache nicht.
Bearbeiten: Wie Stephen C unten angibt, wenn es die Klasse entlädt und beim ersten Mal einen Fehler entdeckt, könnte das erklären, warum es sich nie erholt. Ich denke, das ist eine gute Arbeitstheorie. Ist dies in den Sun-Dokumenten dokumentiert? Warum sollte es nicht protokollieren, dass die Klasse entladen wird, wie es normalerweise beim Entladen einer Klasse ist?
Platform Details:
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
Die ControllerThreadSocketFactory wird initialisiert, und wir bauen HTTP-Verbindungen für einige Zeit vor dem ersten Fehler auf. Im typischen Fall wird die App für mehr als 12 Stunden ausgeführt, bevor der Datenbankverbindungsansturm die Erschöpfung des Dateideskriptors verursacht. Dann erhalten wir die ClassNotFound-Ausnahme, die HTTP-Verbindungen können nicht mehr hergestellt werden, und es wird nie wiederhergestellt. Es scheint, als ob die JVM die Klasse entlädt und sie dann nicht erneut laden kann. –
@Michael ... und der Grund, warum es nicht neu geladen werden kann, ist wie in meiner Antwort angegeben. –
Sie denken also, dass die JVM die Klasse entlädt, wenn sie auf den Fehler trifft? Ist das irgendwo dokumentiert? –