noyau Java: le compilateur HotSpot plante sur SIGSEGV

HotSpot Compiler

Au début, Java VM s'exécute et fonctionne en exécutant le code à exécuter en tant qu'interpréteur, mais il est exécuté en compilant les parties fréquemment exécutées (-XX: CompileThreshold = 10000 ou plus sur Server VM) dans le langage machine natif. Accélère. L'une des causes du plantage de la machine virtuelle Java est qu'un bogue dans ce compilateur HotSpot provoque le blocage du vidage de mémoire SIGSEGV + lors de la tentative de compilation de la méthode cible.

hs_error_log

Parallèlement au vidage de mémoire, les fichiers journaux d'erreurs hs tels que hs_error_log ou hs_err_pid1234.log sont généralement générés. Ce fichier journal contient des informations importantes telles que la méthode que le compilateur HotSpot a tenté de compiler et a abouti à une fin anormale.

La sortie standard se termine par une erreur comme indiqué ci-dessous.

# ulimit -c unlimited
# /usr/libexec/tomcat/server start

# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f5073f646c0, pid=15045, tid=139983466055424
#
# JRE version: OpenJDK Runtime Environment (7.0_141-b02) (build 1.7.0_141-mockbuild_2017_06_13_12_10-b00)
# Java VM: OpenJDK 64-Bit Server VM (24.141-b02 mixed mode linux-amd64 compressed oops)
# Derivative: IcedTea 2.6.10
# Distribution: Red Hat Enterprise Linux Server release 7.3 (Maipo), package rhel-2.6.10.5.el7-x86_64 u141-b02
# Problematic frame:
# V  [libjvm.so+0x8446c0]
#
# Core dump written. Default location: /usr/share/tomcat/core or core.15045
#
# An error report file with more information is saved as:
# /tmp/jvm-15045/hs_error.log
#
# If you would like to submit a bug report, please include
# instructions on how to reproduce the bug and visit:
#   http://icedtea.classpath.org/bugzilla
#
Annuler(Vidage de base)

Vous pouvez voir quelle méthode le compilateur HotSpot a essayé de compiler et s'est écrasé à partir de la partie suivante du fichier journal des erreurs hs:

# vi /tmp/jvm-15045/hs_error.log
...Omission... 
Current CompileTask:
C2: 205800  155             org.apache.tomcat.util.buf.ByteChunk::recycle (21 bytes)
...

Puisque nous forçons la sortie du noyau pour les tests, cette méthode ne conduit généralement pas à un vidage de mémoire. À partir du résultat de sortie ci-dessus, la méthode de la colonne CompileTask: est la méthode cible.

Gérer des problèmes

Pour éviter de tels problèmes avec le compilateur HotSpot, vous pouvez l'éviter en excluant la méthode à compiler du compilateur HotSpot. Créez un fichier .hotspot_compiler dans le répertoire de travail actuel lorsque vous démarrez Java. La machine virtuelle Java lira ce fichier au démarrage, après quoi la méthode spécifiée ne sera pas compilée HotSpot.

# vi .hotspot_compiler
exclude org/apache/tomcat/util/buf/ByteChunk recycle

La plupart des raisons pour lesquelles le compilateur HotSpot s'est écrasé sur SIGSEGV sont des bogues dans Java VM. Cependant, il est très difficile de reproduire le même événement de fin anormale dans un autre environnement. Par conséquent, même si vous contactez le bureau de support Java VM, s'il s'agit d'un nouveau problème qui n'a jamais été vu auparavant, la cause ne peut pas être immédiatement élucidée et on ne peut pas s'attendre à ce qu'elle soit résolue. À ce stade, déterminez si cela se reproduira dans la dernière machine virtuelle Java, et si cela se produit dans la dernière version, envoyez le fichier de base, la bibliothèque liée, le journal des erreurs hs, etc. à la fenêtre de support dans l'espoir qu'il sera corrigé à l'avenir Je pense qu'il sera fourni. Dans un environnement de production, vous devez d'abord définir .hotspot_compiler pour éviter les problèmes.

Vérifiez le nom de la méthode cible dans le fichier core

Vous pouvez vous retrouver dans une situation malheureuse où vous n'avez que le fichier java core à portée de main, comme "j'ai oublié d'obtenir le fichier d'erreur hs" ou "je l'ai déjà supprimé". Même dans ce cas, il est possible de vérifier le nom de la classe cible et le nom de la méthode à partir du fichier core.

Ci-dessous, confirmé dans l'environnement RHEL 7.4 Java 1.7.0_141

$  gdb /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/jre-abrt/bin/java /usr/share/tomcat/core.15045
...Omission...
(gdb) bt
#0  0x00007f50747b01f7 in raise () from /lib64/libc.so.6
#1  0x00007f50747b18e8 in abort () from /lib64/libc.so.6
#2  0x00007f5073f18de9 in os::abort (dump_core=<optimized out>) at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/os/linux/vm/os_linux.cpp:1635
#3  0x00007f50740a7bcf in VMError::report_and_die (this=this@entry=0x7f5070c49bd0)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/utilities/vmError.cpp:1074
#4  0x00007f5073f21ff7 in JVM_handle_linux_signal (sig=11, info=0x7f5070c49e30, ucVoid=0x7f5070c49d00, abort_if_unrecognized=<optimized out>)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp:531
#5  <signal handler called>
#6  0x00007f5073f646c0 in Phase::Phase (this=0x0, pnum=Phase::Compiler)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/opto/phase.cpp:83
#7  0x00007f5073b78711 in Compile::Compile (this=0x0, ci_env=0x7f5070c4ba40, compiler=0x7f506c072730, target=0x7f503c0ba4f0, osr_bci=-1, subsume_loads=<optimized out>, 
    do_escape_analysis=true, eliminate_boxing=true) at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/opto/compile.cpp:683
#8  0x00007f5073ae3d30 in C2Compiler::compile_method (this=0x7f506c072730, env=0x7f5070c4ba40, target=0x7f503c0ba4f0, entry_bci=-1)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/opto/c2compiler.cpp:137
#9  0x00007f5073b7f788 in CompileBroker::invoke_compiler_on_method (task=task@entry=0x7f506c1595c0)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/compiler/compileBroker.cpp:1761
#10 0x00007f5073b80b00 in CompileBroker::compiler_thread_loop ()
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/compiler/compileBroker.cpp:1597
#11 0x00007f5074059cfa in JavaThread::thread_main_inner (this=this@entry=0x7f506c0a8800)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/runtime/thread.cpp:1687
#12 0x00007f507405a07f in JavaThread::run (this=0x7f506c0a8800)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/runtime/thread.cpp:1667
#13 0x00007f5073f17de2 in java_start (thread=0x7f506c0a8800) at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/os/linux/vm/os_linux.cpp:910
#14 0x00007f5074f57e25 in start_thread () from /lib64/libpthread.so.0
#15 0x00007f507487334d in clone () from /lib64/libc.so.6
(gdb)

Il devrait y avoir une fonction C2Compiler :: compile_method comme l'image # 8 dans le thread de compilation ci-dessus. La méthode à compiler est spécifiée comme target = 0x7f503c0ba4f0 dans ce troisième argument. À partir de cette cible, vérifiez le nom de la classe et le nom de la méthode.

python


(gdb) frame 8
#8  0x00007f5073ae3d30 in C2Compiler::compile_method (this=0x7f506c072730, env=0x7f5070c4ba40, target=0x7f503c0ba4f0, entry_bci=-1)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.141-2.6.10.5.el7.x86_64/openjdk/hotspot/src/share/vm/opto/c2compiler.cpp:137
137         Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis, eliminate_boxing);
(gdb)
(gdb) p ({ciMethod}0x7f503c0ba4f0)->_name
$1 = (ciSymbol *) 0x7f503c0ba590
(gdb) p ({ciSymbol}0x7f503c0ba590)->_symbol
$2 = (Symbol *) 0x7f506c4fdb10
(gdb) p &({Symbol}0x7f506c4fdb10)->_body
$3 = (signed char (*)[1]) 0x7f506c4fdb1a
(gdb) x/s 0x7f506c4fdb1a
0x7f506c4fdb1a: "recycle"
(gdb) 

Nom de la méthode"recycle"était.

(gdb) p ({ciMethod}0x7f503c0ba4f0)->_holder
$21 = (ciInstanceKlass *) 0x7f503c0ba5a0
(gdb) p ({ciInstanceKlass}0x7f503c0ba5a0)->_name
$22 = (ciSymbol *) 0x7f503c0ba630
(gdb) p ({ciSymbol}0x7f503c0ba630)->_symbol
$23 = (Symbol *) 0x7f506c529af0
(gdb) p &({Symbol}0x7f506c529af0)->_body
$24 = (signed char (*)[1]) 0x7f506c529afa
(gdb) x/s 0x7f506c529afa
0x7f506c529afa: "org/apache/tomcat/util/buf/ByteChunk"
(gdb) 

nom de la classe"org/apache/tomcat/util/buf/ByteChunk"était.

C'était une confirmation à tâtons, mais c'était gênant, alors j'ai écrit un simple script Python. https://github.com/takimai39/gdb-java

(gdb) source target.py
(gdb) target 0x7f503c0ba4f0
exclude org/apache/tomcat/util/buf/ByteChunk recycle
(gdb) 

J'espère que tu trouves cela utile.

Recommended Posts

noyau Java: le compilateur HotSpot plante sur SIGSEGV
noyau java: compilateur HotSpot et tas C
[Java] Comment résoudre un bogue dans le compilateur JDK
Installez Java sur Mac
Exécutez PostgreSQL sur Java
noyau java: fichier de base haché
Brainfuck-> Compilateur de code d'octet Java