java core: Vous ne pouvez pas atteindre safepoint et vous bloquer? !!

Cas de blocage JVM où le vidage de thread ne peut pas être généré

Il est ambigu de déterminer ce qui a causé le blocage, mais en général, pour l'événement "JVM bloqué?", Kill -QUIT ne génère pas de vidage de thread ou de vidage de thread. Est sortie, mais la réponse à la demande est divisée en phénomène qu'elle ne renvoie pas, peu importe combien de temps vous attendez. `Cet article décrit un modèle qui ne génère pas non plus de vidage de thread. '' Si un vidage de thread est généré, Java raccroche? Veuillez également vous y référer.

safepoint

Lorsque la machine virtuelle Java génère un vidage de thread ou effectue un GC complet, tous les threads Java en cours d'exécution sont traités vers un emplacement appelé safepoint, puis l'opération souhaitée est effectuée. Lorsqu'une machine virtuelle Java se bloque parce qu'elle ne peut pas générer un vidage de thread, il arrive souvent que ce point de restauration ne puisse pas être atteint, et la vérification de l'état des threads individuels peut aider à identifier la cause.

Vérifiez SafepointStatus pour chaque thread Java

Je suis désolé pour le désagrément, mais j'ai créé un script python gdb qui affiche le SafepointStatus pour chaque JavaThread. https://github.com/takimai39/gdb-java

Afficher le cœur de la machine virtuelle Java bloquée

Exécutons le code sur https://bugs.openjdk.java.net/browse/JDK-8064749 pour créer une situation où il se bloque réellement.

$ java -XX:-UseCompilerSafepoints Stuck
^Z
[1]+Arrêter java-XX:-UseCompilerSafepoints Stuck
$ kill -QUIT %1

[1]+Arrêter java-XX:-UseCompilerSafepoints Stuck
$ fg
java -XX:-UseCompilerSafepoints Stuck

Suspendre avec CTRL + Z, envoyer kill -QUIT et revenir avec fg, mais aucun vidage de thread n'est craché. Obtenez le noyau et vérifiez l'état du safepoint

$ jps
29617 Stuck
29657 Jps
$ gcore 29617
...
Saved corefile core.29617
$ gdb /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.131-11.b12.el7.x86_64/bin/java ./core.29617
...
(gdb) source sp.py
(gdb) safepoint
--------------------------------------------------------------------
Status:                 SafepointSynchronize::_synchronizing
waiting to block:       1
LWP     Java Thread Name        Status
--------------------------------------------------------------------
LWP 29618 DestroyJavaVM          ThreadSafepointState::_at_safepoint
LWP 29630 Timer                  ThreadSafepointState::_at_safepoint
LWP 29629 Worker                 ThreadSafepointState::_running
LWP 29627 Service Thread         ThreadSafepointState::_at_safepoint
LWP 29626 C1 CompilerThread1     ThreadSafepointState::_at_safepoint
LWP 29625 C2 CompilerThread0     ThreadSafepointState::_at_safepoint
LWP 29624 Signal Dispatcher      ThreadSafepointState::_at_safepoint
LWP 29623 ?                      ThreadSafepointState::_at_safepoint
LWP 29622 Reference Handler      ThreadSafepointState::_at_safepoint
(gdb)

SafepointSynchronize :: _state est en cours de _synchronisation, donc la JVM essaie de conserver tous les JavaThreads dans safepoint. Cependant, étant donné que l'attente de blocage est égale à 1, un thread n'a pas encore atteint le point de restauration. Bien entendu, les fonctionnalités de la JVM qui doivent également aller au point de restauration, telles que les vidages de thread, ne fonctionneront pas dans cette situation. Dans ce cas, le thread sur LWP 29629 se bloque.

Vérifiez la pile avec le dérouleur OpenJDK

https://qiita.com/takimai39/items/a78b7a64a501d77efed8 Vérifions la pile du thread cible (LWP 29629) avec ce dérouleur OpenJDK.

(gdb) source dbg8.py
Installing openjdk unwinder
(gdb) source sp.py
(gdb) info thread
  Id   Target Id         Frame 
  14   Thread 0x7f373cd10700 (LWP 29630) 0x00007f3756e55945 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  13   Thread 0x7f373ce11700 (LWP 29629) 0x00007f3741109660 in ?? ()
  12   Thread 0x7f373cf12700 (LWP 29628) 0x00007f3756e55cf2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  11   Thread 0x7f373d013700 (LWP 29627) 0x00007f3756e55945 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  10   Thread 0x7f373d114700 (LWP 29626) 0x00007f3756e55945 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  9    Thread 0x7f373d215700 (LWP 29625) 0x00007f3756e55945 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  8    Thread 0x7f373d316700 (LWP 29624) 0x00007f3756e55945 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  7    Thread 0x7f373d417700 (LWP 29623) 0x00007f3756e55945 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  6    Thread 0x7f373d518700 (LWP 29622) 0x00007f3756e55945 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  5    Thread 0x7f373d619700 (LWP 29621) 0x00007f375653ae47 in sched_yield () from /lib64/libc.so.6
  4    Thread 0x7f3740a02700 (LWP 29620) 0x00007f3756e55945 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  3    Thread 0x7f3740b03700 (LWP 29619) 0x00007f3756e55945 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
  2    Thread 0x7f375726d700 (LWP 29618) 0x00007f3756e55945 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
* 1    Thread 0x7f375726e740 (LWP 29617) 0x00007f3756e52f57 in pthread_join () from /lib64/libpthread.so.0
(gdb) thread 13
[Switching to thread 13 (Thread 0x7f373ce11700 (LWP 29629))]
#0  0x00007f3741109660 in ?? ()
(gdb) bt
#0  0x00007f3741109660 in [compiled offset=0x40] Stuck$Worker.run() () at Stuck.java:35
#1  0x00007f37410004e7 in StubRoutines (1) ()
#2  0x00007f3755b12b4a in JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) (result=0x7f373ce10dc0, m=<optimized out>, args=<optimized out>, __the_thread__=0x7f37500ea800) at /usr/src/debug/java-1.8.0-openjdk-1.8.0.131-11.b12.el7.x86_64/openjdk/hotspot/src/share/vm/runtime/javaCalls.cpp:406
#3  0x00007f3755b0ffe4 in JavaCalls::call_virtual(JavaValue*, KlassHandle, Symbol*, Symbol*, JavaCallArguments*, Thread*) (__the_thread__=0x7f37500ea800, args=0x7f373ce10d30, method=<error reading variable: access outside bounds of object referenced via synthetic pointer>, result=0x7f373ce10dc0)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.131-11.b12.el7.x86_64/openjdk/hotspot/src/share/vm/runtime/javaCalls.cpp:307
#4  0x00007f3755b0ffe4 in JavaCalls::call_virtual(JavaValue*, KlassHandle, Symbol*, Symbol*, JavaCallArguments*, Thread*) (result=result@entry=0x7f373ce10dc0, spec_klass=..., name=<optimized out>, signature=<optimized out>, args=args@entry=0x7f373ce10d30, __the_thread__=__the_thread__@entry=0x7f37500ea800)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.131-11.b12.el7.x86_64/openjdk/hotspot/src/share/vm/runtime/javaCalls.cpp:204
#5  0x00007f3755b105f9 in JavaCalls::call_virtual(JavaValue*, Handle, KlassHandle, Symbol*, Symbol*, Thread*) (result=result@entry=0x7f373ce10dc0, receiver=..., spec_klass=..., name=<optimized out>, signature=<optimized out>, __the_thread__=__the_thread__@entry=0x7f37500ea800)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.131-11.b12.el7.x86_64/openjdk/hotspot/src/share/vm/runtime/javaCalls.cpp:210
#6  0x00007f3755b55301 in thread_entry(JavaThread*, Thread*) (thread=<optimized out>, __the_thread__=0x7f37500ea800)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.131-11.b12.el7.x86_64/openjdk/hotspot/src/share/vm/prims/jvm.cpp:2974
#7  0x00007f3755ef4c72 in JavaThread::thread_main_inner() (this=0x7f37500ea800)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.131-11.b12.el7.x86_64/openjdk/hotspot/src/share/vm/runtime/thread.cpp:1710
#8  0x00007f3755d4be12 in java_start(Thread*) (thread=0x7f37500ea800)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.131-11.b12.el7.x86_64/openjdk/hotspot/src/os/linux/vm/os_linux.cpp:790
#9  0x00007f3756e51e25 in start_thread () at /lib64/libpthread.so.0
#10 0x00007f375655634d in clone () at /lib64/libc.so.6
(gdb)

frame # 0 est la 35ème ligne de Stuck.java, qui est une boucle serrée avec while () comme indiqué ci-dessous. Il a été compilé en code natif par HotSpot car il dit compilé. En d'autres termes, c'est l'opération cible pour laquelle la spécification de "-XX: -UseCompilerSafepoints" est effective. (Par défaut, c'est + UseCompilerSafepoints, donc vous ne rencontrerez probablement pas ce problème.)

 33         @Override
 34         public void run() {
 35             while (!isDone) { // <--ici!
 36                 // burn
 37             }
 38         }

Dans le cas d'un blocage de la JVM qui ne peut pas générer un vidage de thread, il est possible de trouver le thread de cause et le contenu de traitement en vérifiant le statut de safepoint pour chaque JavaThread de cette manière.

Recommended Posts

java core: Vous ne pouvez pas atteindre safepoint et vous bloquer? !!
Java raccroche?
Java et JavaScript
XXE et Java
Getter et Setter (Java)
[Java] Thread et exécutable
Java vrai et faux
[Java] Comparaison des chaînes de caractères et && et ||
noyau java: fichier de base haché
Java - Sérialisation et désérialisation
[Java] Arguments et paramètres
timedatectl et Java TimeZone
[Java] Branchement et répétition
[Java] Types de variables et types
java (classe et instance)
[Java] Surcharge et remplacement