2010-03-21 10 views
5

Dans certaines circonstances bien comprises, notre application ouvrira trop de sockets (connexions de base de données) et atteindra le maximum de fichiers ouverts que le système d'exploitation permet. Nous comprenons cela; Nous sommes en train de régler le problème et de relever la limite. Ce que nous ne pouvons pas expliquer est pourquoi certaines parties de notre application ne se rétablissent pas même après que le nombre de connexions diminue et nous sommes bien dans la limite.Pourquoi la machine virtuelle Java ne récupère pas après les erreurs "Trop de fichiers ouverts"?

Dans ce cas, il s'agit d'une application fonctionnant sous Tomcat.

Lorsque cela se produit, nous avons d'abord commencer à voir « Trop de fichiers ouverts » erreurs:

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) 

Finalement, nous commençons à voir NoClassDefFoundError s à l'intérieur d'un fil d'application qui essaie d'ouvrir les connexions HTTP:

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 

Lorsque les connexions errantes disparaissent, le serveur recommence à accepter les connexions, et tout semble correct, mais il nous reste la dernière erreur constamment envoyée à stderr.

Bien que l'application enregistre généralement des classes déchargées dans stdout, je ne vois pas de tels journaux juste avant, pendant ou après les erreurs «Trop de fichiers ouverts». Ma théorie initiale était que la JVM Hotspot déchargerait des classes apparemment inutilisées quand elle rencontrerait «Trop de fichiers ouverts», mais si c'est le cas, elle n'enregistre pas le fait. Comme Stephen C l'indique ci-dessous, s'il décharge la classe et rencontre une erreur lors du premier rechargement, cela pourrait expliquer pourquoi il ne récupère jamais. Je pense que c'est une bonne théorie de travail. Est-ce documenté dans les docs de Sun? Pourquoi ne consignerait-il pas que la classe est déchargée de la même façon que le déchargement d'une classe?

détails de la plate-forme:

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 

Répondre

1

Je pense que la raison pour laquelle vous obtenez ClassNotFoundExceptions répétées est que la première initialisation de classe tentative de ControllerThreadSocketFactory a échoué en raison du problème de fuite de Socket. Votre code fait maintenant des choses à plusieurs reprises qui redéclenche l'initialisation de classe pour la classe, et ils rapportent le problème original.

Si une initialisation de classe échoue la première fois, c'est tout. La JVM n'essaiera pas de le refaire.

+0

Le ControllerThreadSocketFactory est initialisé et nous établissons des connexions HTTP pendant un certain temps avant la première erreur. Dans le cas typique, l'application s'exécute pendant plus de 12 heures avant la fin de la connexion à la base de données qui provoque l'épuisement du descripteur de fichier. Ensuite, nous obtenons l'exception ClassNotFound, les connexions HTTP ne peuvent plus être établies, et il ne récupère jamais. Il semble que la machine virtuelle Java décharge la classe et ne peut pas la recharger. –

+0

@Michael ... et la raison pour laquelle il ne peut pas le recharger est comme indiqué dans ma réponse. –

+0

Donc vous pensez aussi que la JVM décharge la classe quand elle rencontre l'erreur? Est-ce documenté quelque part? –

0

En faisant face au même problème en utilisant Weblogic 8.1/JRockIt R27.2 et un tas de webapps qui essaye de charger des resourcebundles, puis échoue en raison de la limite sur le nombre de fichiers ouverts. L'arrêt et le démarrage de l'application (c'est-à-dire le déchargement et le chargement des classloaders) font que les choses fonctionnent à nouveau.