В этой статье я покажу вам, как вы можете отладить основной файл 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=3fe0000000000000018kNative frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)C [libnativelib.so+0x75c] bar+0x10C [libnativelib.so+0x772] foo+0xeC [libnativelib.so+0x78e] Java_CoreDumper_core+0x1aj CoreDumper.core()V+0j CoreDumper.main([Ljava/lang/String;)V+7v ~StubRoutines::call_stubV [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/coresjava.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.coreDebugger attached successfully.Server compiler detected.JVM version is 17.0-b16Deadlock 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.coreDebugger attached successfully.Server compiler detected.JVM version is 17.0-b160x0000000040000000 49K /usr/sunjdk/1.6.0_21/bin/java0x0000002a9566c000 124K /lib64/tls/libpthread.so.00x0000002a95782000 47K /usr/sunjdk/1.6.0_21/jre/lib/amd64/jli/libjli.so0x0000002a9588c000 16K /lib64/libdl.so.20x0000002a9598f000 1593K /lib64/tls/libc.so.60x0000002a95556000 110K /lib64/ld-linux-x86-64.so.20x0000002a95bca000 11443K /usr/sunjdk/1.6.0_21/jre/lib/amd64/server/libjvm.so0x0000002a96699000 625K /lib64/tls/libm.so.60x0000002a9681f000 56K /lib64/tls/librt.so.10x0000002a96939000 65K /usr/sunjdk/1.6.0_21/jre/lib/amd64/libverify.so0x0000002a96a48000 228K /usr/sunjdk/1.6.0_21/jre/lib/amd64/libjava.so0x0000002a96b9e000 109K /lib64/libnsl.so.10x0000002a96cb6000 54K /usr/sunjdk/1.6.0_21/jre/lib/amd64/native_threads/libhpi.so0x0000002a96de8000 57K /lib64/libnss_files.so.20x0000002a96ef4000 551K /lib64/libnss_db.so.20x0000002a97086000 89K /usr/sunjdk/1.6.0_21/jre/lib/amd64/libzip.so0x0000002b1cecf000 6K /home/sharfah/tmp/jni/libnativelib.so |
Полезные ссылки:
Ускоренный курс по анализу сбоев JVM
Генерация дампа ядра Java
Ссылка: Анализ основного дампа Java от нашего партнера по JCG Фахда Шарифа в блоге fahd.blog .