В этой статье я покажу вам, как вы можете отладить основной файл Java, чтобы увидеть, что вызвало сбой вашей JVM. Я буду использовать основной файл, сгенерированный в моем предыдущем посте: Генерация Java Core Dump . Существует несколько способов диагностики сбоя JVM, перечисленных ниже:
Файл журнала hs_err_pid
Когда в JVM происходит неустранимая ошибка, он создает файл журнала ошибок с именем hs_err_pidXXXX.log
, обычно в рабочем каталоге процесса или во временном каталоге операционной системы. Верхняя часть этого файла содержит причину сбоя и «проблемный кадр». Например, мои шоу:
01
02
03
04
05
06
07
08
09
10
11
|
$ head hs_err_pid21178.log # # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x0000002b1d00075c, pid=21178, tid=1076017504 # # JRE version: 6.0_21-b06 # Java VM: Java HotSpot(TM) 64-Bit Server VM (17.0-b16 mixed mode linux-amd64 ) # Problematic frame: # C [libnativelib.so+0x75c] bar+0x10 # |
Также есть трассировка стека:
1
2
3
4
5
6
7
8
9
|
Stack: [0x000000004012b000,0x000000004022c000], sp=0x000000004022aac0, free space=3fe0000000000000018k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) C [libnativelib.so+0x75c] bar+0x10 C [libnativelib.so+0x772] foo+0xe C [libnativelib.so+0x78e] Java_CoreDumper_core+0x1a j CoreDumper.core()V+0 j CoreDumper.main([Ljava /lang/String ;)V+7 v ~StubRoutines::call_stub V [libjvm.so+0x3e756d] |
Трассировка стека показывает, что мой java-метод CoreDumper.core()
вызвал JNI и умер, когда функция bar
была вызвана в собственном коде
Отладка дампа ядра Java
В некоторых случаях JVM может не создавать файл hs_err_pid
, например, если собственный код прерывается внезапно, вызывая функцию abort
. В таких случаях нам нужно проанализировать полученный файл ядра. На моей машине операционная система записывает файлы ядра в /var/tmp/cores
. Вы можете использовать следующую команду, чтобы увидеть, где настроена ваша система для записи основных файлов:
1
2
3
4
|
$ cat /proc/sys/kernel/core_pattern /var/tmp/cores/ %e.%p.%u.core $ ls /var/tmp/cores java.21178.146385.core |
Существует несколько разных способов просмотра дампов ядра:
1. Использование GDB
Отладчик GNU (gdb) может проверить файл ядра и выяснить, что программа делала в случае сбоя.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
$ gdb $JAVA_HOME /bin/java /var/tmp/cores/java .14015.146385.core ( gdb ) where #0 0x0000002a959bd26d in raise () from /lib64/tls/libc.so.6 #1 0x0000002a959bea6e in abort () from /lib64/tls/libc.so.6 #2 0x0000002b1cecf799 in bar () from libnativelib.so #3 0x0000002b1cecf7a7 in foo () from libnativelib.so #4 0x0000002b1cecf7c3 in Java_CoreDumper_core () from libnativelib.so #5 0x0000002a971aac88 in ?? () #6 0x0000000040113800 in ?? () #7 0x0000002a9719fa42 in ?? () #8 0x000000004022ab10 in ?? () #9 0x0000002a9a4d5488 in ?? () #10 0x000000004022ab70 in ?? () #11 0x0000002a9a4d59c8 in ?? () #12 0x0000000000000000 in ?? () |
Команда where
печатает кадры стека и показывает, что функция bar
называется abort()
которая вызвала сбой.
2. Использование jstack
jstack
печатает трассировки стека потоков Java для данного файла ядра.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
$ jstack -J-d64 $JAVA_HOME /bin/java /var/tmp/cores/java .14015.146385.core Debugger attached successfully. Server compiler detected. JVM version is 17.0-b16 Deadlock Detection: No deadlocks found. Thread 16788: (state = BLOCKED) Thread 16787: (state = BLOCKED) - java.lang.Object.wait(long) @bci=0 (Interpreted frame) - java.lang.ref.ReferenceQueue.remove(long) @bci=44, line=118 (Interpreted frame) - java.lang.ref.ReferenceQueue.remove() @bci=2, line=134 (Interpreted frame) - java.lang.ref.Finalizer$FinalizerThread.run() @bci=3, line=159 (Interpreted frame) Thread 16786: (state = BLOCKED) - java.lang.Object.wait(long) @bci=0 (Interpreted frame) - java.lang.Object.wait() @bci=2, line=485 (Interpreted frame) - java.lang.ref.Reference$ReferenceHandler.run() @bci=46, line=116 (Interpreted frame) Thread 16780: (state = IN_NATIVE) - CoreDumper.core() @bci=0 (Interpreted frame) - CoreDumper.main(java.lang.String[]) @bci=7, line=12 (Interpreted frame) |
3. Использование jmap
jmap
проверяет файл ядра и распечатывает карты памяти общих объектов или детали памяти кучи.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
$ jmap -J-d64 $JAVA_HOME /bin/java /var/tmp/cores/java .14015.146385.core Debugger attached successfully. Server compiler detected. JVM version is 17.0-b16 0x0000000040000000 49K /usr/sunjdk/1 .6.0_21 /bin/java 0x0000002a9566c000 124K /lib64/tls/libpthread .so.0 0x0000002a95782000 47K /usr/sunjdk/1 .6.0_21 /jre/lib/amd64/jli/libjli .so 0x0000002a9588c000 16K /lib64/libdl .so.2 0x0000002a9598f000 1593K /lib64/tls/libc .so.6 0x0000002a95556000 110K /lib64/ld-linux-x86-64 .so.2 0x0000002a95bca000 11443K /usr/sunjdk/1 .6.0_21 /jre/lib/amd64/server/libjvm .so 0x0000002a96699000 625K /lib64/tls/libm .so.6 0x0000002a9681f000 56K /lib64/tls/librt .so.1 0x0000002a96939000 65K /usr/sunjdk/1 .6.0_21 /jre/lib/amd64/libverify .so 0x0000002a96a48000 228K /usr/sunjdk/1 .6.0_21 /jre/lib/amd64/libjava .so 0x0000002a96b9e000 109K /lib64/libnsl .so.1 0x0000002a96cb6000 54K /usr/sunjdk/1 .6.0_21 /jre/lib/amd64/native_threads/libhpi .so 0x0000002a96de8000 57K /lib64/libnss_files .so.2 0x0000002a96ef4000 551K /lib64/libnss_db .so.2 0x0000002a97086000 89K /usr/sunjdk/1 .6.0_21 /jre/lib/amd64/libzip .so 0x0000002b1cecf000 6K /home/sharfah/tmp/jni/libnativelib .so |
Полезные ссылки:
Ускоренный курс по анализу сбоев JVM
Генерация дампа ядра Java
Ссылка: Анализ основного дампа Java от нашего партнера по JCG Фахда Шарифа в блоге fahd.blog .