2013-05-28 41 views
8

Próba debugowania niewłaściwie pracującej maszyny wirtualnej Java. Omawiany proces to duża maszyna wirtualna (stup 100 GB) z uruchomioną Sun VM 1.6u24 na komputerze Centos 5, która wykonuje rutynowe prace back-end - tj. Dostęp do baz danych, operacje na plikach i tak dalej.JVM okresowo zawiesza się

Po ponownym uruchomieniu procesu w celu aktualizacji wersji oprogramowania zauważyliśmy, że jego przepustowość znacznie spadła. Przez większość czasu najlepsze raporty, że proces Java w pełni wykorzystuje 2 rdzenie. W tym czasie maszyna wirtualna jest całkowicie nieodpowiedzialna: nie są zapisywane żadne dzienniki i nie reaguje na narzędzia zewnętrzne, takie jak jstack lub kill -3. Po odzyskaniu VM proces trwa tak jak zwykle, aż do następnego zawieszenia.

strace pokazuje, że podczas tych zawieszek tylko 2 wątki wywołują wywołania systemowe. Były to wątki VM "Wątek VM" (21776) i "Okresowy wątek zadań VM" (21786). Przypuszczalnie te 2 wątki zużywają czas procesora. Nitki aplikacji czasami się budzą i wykonują swoją pracę. Resztę czasu wydają się czekać na różne futexy. Nawiasem mówiąc, pierwszą linią fazy normalnej jest zawsze SIGSEGV.

[pid 21776] sched_yield()    = 0 
[pid 21776] sched_yield()    = 0 
[pid 21776] sched_yield(<unfinished ...> 
[pid 21786] <... futex resumed>)  = -1 ETIMEDOUT (Connection timed out) 
[pid 21776] <... sched_yield resumed>) = 0 
[pid 21786] futex(0x2aabac71ef28, FUTEX_WAKE_PRIVATE, 1 <unfinished ...> 
[pid 21776] sched_yield(<unfinished ...> 
[pid 21786] <... futex resumed>)  = 0 
[pid 21786] clock_gettime(CLOCK_MONOTONIC, {517080, 280918033}) = 0 
[pid 21786] clock_gettime(CLOCK_REALTIME, {1369750039, 794028000}) = 0 
[pid 21786] futex(0x2aabb81b94c4, FUTEX_WAIT_PRIVATE, 1, {0, 49923000} <unfinished ...> 
[pid 21776] <... sched_yield resumed>) = 0 
[pid 21776] sched_yield()    = 0 
[pid 21776] sched_yield()    = 0 
[pid 21955] --- SIGSEGV (Segmentation fault) @ 0 (0) --- 
[pid 21955] rt_sigreturn(0x2b1cde2f54ad <unfinished ...> 

Problem występuje na 2 różnych serwerach. Wycofanie wersji kodu działa tylko na jednym z dwóch serwerów. W dziennikach systemowych nie zgłoszono żadnych komunikatów o błędach, a inny proces Java na zaatakowanym komputerze zachowuje się poprawnie.

Ten następujące wyniki uzyskano z gstack 2 i pokazuje typowe wątki aplikacji oczekujących:

Thread 552 (Thread 0x4935f940 (LWP 21906)): 
#0 0x00000030b040ae00 in [email protected]@GLIBC_2.3.2() from /lib64/libpthread.so.0 
#1 0x00002b1cdd8548d6 in os::PlatformEvent::park(long)() from /usr/lib/jvm/java/jre/lib/amd64/server/libjvm.so 
#2 0x00002b1cdd92b230 in ObjectMonitor::wait(long, bool, Thread*)() from /usr/lib/jvm/java/jre/lib/amd64/server/libjvm.so 
#3 0x00002b1cdd928853 in ObjectSynchronizer::wait(Handle, long, Thread*)() from /usr/lib/jvm/java/jre/lib/amd64/server/libjvm.so 
#4 0x00002b1cdd69b716 in JVM_MonitorWait() from /usr/lib/jvm/java/jre/lib/amd64/server/libjvm.so 
#5 0x00002b1cde193cc8 in ??() 
#6 0x00002b1ce2552d90 in ??() 
#7 0x00002b1cdd84fc23 in os::javaTimeMillis()() from /usr/lib/jvm/java/jre/lib/amd64/server/libjvm.so 
#8 0x00002b1cde188a82 in ??() 
#9 0x0000000000000000 in ??() 
Thread 551 (Thread 0x49460940 (LWP 21907)): 
#0 0x00000030b040ab99 in [email protected]@GLIBC_2.3.2() from /lib64/libpthread.so.0 
#1 0x00002b1cdd854d6f in Parker::park(bool, long)() from /usr/lib/jvm/java/jre/lib/amd64/server/libjvm.so 
#2 0x00002b1cdd98a1c8 in Unsafe_Park() from /usr/lib/jvm/java/jre/lib/amd64/server/libjvm.so 
#3 0x00002b1cde193cc8 in ??() 
#4 0x000000004945f798 in ??() 
#5 0x00002b1cde188a82 in ??() 
#6 0x0000000000000000 in ??() 

Przyjrzeliśmy problemów z ntpd, w tym przestępne drugich błędów, ale jak je obejść nie pomoże, ani nie stosując zewnętrzne serwery NTPD. Ponowne uruchomienie maszyny również nie pomogło. Mamy włączone rejestrowanie GC i nie wygląda to na problem z GC, ponieważ nie ma tam żadnych komunikatów. Poszukując wszelkich sugestii, które mogą pomóc w tym problemie, każda pomoc jest bardzo doceniana.

+1

Czy to możliwe, że "GC pauza"? czy użyłeś algorytmu GC? http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html#0.0.0.%20The%20Concurrent%20Low%20Pause%20Collector%7Coutline – kosa

+0

Zgadzam się z @Nambari - mam zaobserwowano bardzo długie przerwy w dużych maszynach JVM, gdy są one obciążone. Jeśli proces GC nie zakończy się w rozsądnym czasie, może wystąpić błąd braku pamięci. Czy twój JVM naprawdę musi być tak duży? –

+0

Im większa sterta, tym więcej obiektów musi zostać rozwiązanych przez proces GC. –

Odpowiedz

3

Oto kilka rzeczy bym spojrzeć na:

  • Kiedy JVM nie odpowiada, należy iostat i vmstat aby sprawdzić, czy system jest cięgi. Może się to zdarzyć, gdy nadmiar pamięci zostanie przydzielony; np. Twój ogólny system używa znacznie więcej pamięci wirtualnej niż pamięci fizycznej.

  • Włącz rejestrowanie GC maszyny JVM i zobacz, czy istnieje korelacja między maszyną JVM przestającą odpowiadać i przebiegami GC.

Powiązane problemy