W pewnych dobrze zrozumiałych okolicznościach nasza aplikacja otworzy zbyt wiele gniazd (połączeń z bazami danych) i osiągnie maksymalne otwarte pliki, na które pozwala system operacyjny. Rozumiemy to; naprawiamy problem, a także podnosimy limit.Dlaczego wirtualna maszyna wirtualna Java nie jest odtwarzana po błędach "Zbyt wiele otwartych plików"?
Nie możemy wyjaśnić, dlaczego niektóre części naszej aplikacji nie są odzyskiwane nawet po zaniku liczby połączeń, a my osiągnęliśmy limit.
W tym przypadku jest to aplikacja działająca pod Tomcat.
Kiedy to nastąpi, musimy najpierw zacząć widzieć „Zbyt wiele otwartych plików” błędów:
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)
końcu zaczniemy widząc NoClassDefFoundError
s wewnątrz wątku aplikacji, która próbuje otworzyć połączenia 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
Gdy błędne połączenia znikną, serwer ponownie zacznie akceptować połączenia, a wszystko wydaje się być w porządku, ale pozostaniemy z tym ostatnim błędem nieustannie wypluwanym na stderr.
Mimo że aplikacja zazwyczaj rejestruje nieobciążone klasy na standardowe wyjście, nie widzę takich dzienników tuż przed, podczas lub po błędach "Zbyt wiele otwartych plików".
Moja wstępna teoria głosiła, że JVM Hotspot rozładowałby pozornie nieużywane klasy, gdy napotka "Zbyt wiele otwartych plików", ale jeśli tak, to nie rejestruje tego faktu.
Edit: Jako Stephen C wskazuje poniżej, jeśli jest rozładunku klasę i napotka błąd po raz pierwszy go przeładowuje, które mogłyby wyjaśnić, dlaczego nigdy nie odzyskuje. Myślę, że to dobra teoria pracy. Czy jest to udokumentowane w dokumentach Sun? Dlaczego nie logowałby się, że klasa jest rozładowywana w taki sposób, jak zwykle ma to miejsce w przypadku wyładowania klasy?
szczegóły Platforma:
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
Zainicjowano ControllerThreadSocketFactory i nawiązujemy połączenia HTTP przez pewien czas przed pierwszym błędem. W typowym przypadku aplikacja działa przez ponad 12 godzin przed utratą połączenia z bazą danych, co powoduje wyczerpanie deskryptora pliku. Następnie otrzymujemy wyjątek ClassNotFound, połączenia HTTP nie mogą być ustanowione i nigdy się nie odzyskuje. Wygląda na to, że JVM rozładowuje klasę, a następnie nie może jej ponownie załadować. –
@Michael ... a powodem, dla którego nie może go ponownie załadować, jest to, co podano w mojej odpowiedzi. –
Więc myślisz, że JVM rozładowuje klasę, gdy napotka błąd? Czy to gdzieś dokumentuje? –