當 JVM 發生嚴重錯誤(如 Segmentation Fault)導致進程崩潰時,會自動生成一份命名為 hs_err_pid<pid>.log 的錯誤日誌檔案。這份日誌包含了診斷崩潰根因的關鍵資訊,是排查 JVM Crash、Native Memory 問題、JNI 錯誤的核心依據。本文將以一份實際的 Linux 環境下 Eclipse 崩潰日誌為例,逐段深度解析各區塊含義與排查思路。
/tmp)-XX:ErrorFile=/var/log/java/Java_error%p.log(%p 代表 PID)# SIGSEGV (0xb) at pc=0x03568cf4, pid=16819, tid=3073346448
| 欄位 | 含義 | |
|---|---|---|
SIGSEGV | 信號名稱:Segmentation Fault(記憶體存取違規) | |
0xb | 信號編號(Linux x86 上 SIGSEGV = 11 = 0xb) | |
pc=0x03568cf4 | 程式計數器值,崩潰時正在執行的指令位址 | |
pid=16819 | 進程 ID | |
| tid=3073346448 | 線程 ID(Linux 下為 pthread_t 數值) |
關鍵判斷:SIGSEGV 通常意味著 Native 代碼(JNI、Native 庫、JVM 本身)嘗試存取無效記憶體位址。
# JRE version: 6.0_32-b05
# Java VM: Java HotSpot(TM) Server VM (20.7-b02 mixed mode Linux-x86 )
確認 JDK 版本、VM 模式(Server/Client)、混合模式(Mixed Mode:解釋執行 + JIT 編譯)、作業系統架構。排查時請優先對照已知 Bug 數據庫(如 Oracle Bug Database)。
# Problematic frame:
# C [libgtk-x11-2.0.so.0+0x19fcf4] __float128+0x19fcf4
| 幀類型 | 說明 |
|---|---|
| C | Native C/C++ 幀(最常見於 JNI、Native 庫、JVM 運行時) |
| j | 解釋執行的 Java 幀 |
| V | VM 內部幀 |
| J | JIT 編譯後的 Java 幀 |
| v | VM 生成的存根幀 |
關鍵線索:此處 C 幀指向 libgtk-x11-2.0.so.0(GTK 圖形庫),偏移量 0x19fcf4。結合 pc 值,可定位至具體 Native 函數。此例顯示 Eclipse SWT 呼叫 GTK 導致崩潰。
Current thread (0x09f30c00): JavaThread "main" [_thread_in_native, id=16822, stack(0xb72a8000,0xb72f9000)]
0x09f30c00:JVM 內部線程物件指標JavaThread:線程類型(其他:VMThread、CompilerThread、GCTaskThread 等)main:線程名稱_thread_in_native:關鍵狀態,表示崩潰發生在 Native 代碼執行期間,強烈暗示 Native 代碼或 JNI 問題stack(0xb72a8000,0xb72f9000):線程棧記憶體範圍siginfo: si_signo=SIGSEGV: si_errno=0, si_code=1 (SEGV_MAPERR), si_addr=0x00000010
EAX=0x00000000, EBX=0x0375dd84, ECX=0x00000000, EDX=0x00000000
ESP=0xb72f0fa0, EBP=0xb72f0fb8, ESI=0x00000000, EDI=0x0a6c1800
EIP=0x03568cf4, EFLAGS=0x00010246, CR2=0x00000010
si_code=1 (SEGV_MAPERR):存取的位址未映射(非權限錯誤)si_addr=0x10:嘗試存取的無效位址(極小值通常暗示 NULL 指標解引用且帶偏移)EIP=pc:指令指標寄存器,指向崩潰指令ESP/EBP:棧指標/基址指標,用於棧回溯Instructions: (pc=0x03568cf4)
0x03568cd4: 89 14 24 89 75 f8 89 d6 89 7d fc 89 c7 e8 7e 1b
0x03568ce4: ea ff 89 34 24 89 87 d4 02 00 00 e8 30 00 ea ff
0x03568cf4: 8b 40 10 89 3c 24 c7 44 24 08 00 00 00 00 89 87
0x03568d04: d0 02 00 00 8b 83 88 24 00 00 89 44 24 04 e8 dd
崩潰位址附近的機器碼,可用反組譯工具(如 objdump、gdb)轉為組合語言,進一步分析具體指令行為。
Register to memory mapping:
EAX=0x00000000 is an unknown value
EBX=0x0375dd84: in /usr/lib/libgtk-x11-2.0.so.0 at 0x033c9000
ESP=0xb72f0fa0 is pointing into the stack for thread: 0x09f30c00
EBP=0xb72f0fb8 is pointing into the stack for thread: 0x09f30c00
關鍵發現:EBX 指向 libgtk-x11-2.0.so.0 內部位址,佐證崩潰發生在 GTK 庫內部。
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [libgtk-x11-2.0.so.0+0x19fcf4] __float128+0x19fcf4
C [libgtk-x11-2.0.so.0+0x1a32c0] __float128+0xc0
...
C [libswt-pi-gtk-3738.so+0x33f6a] Java_org_eclipse_swt_internal_gtk_OS__1Call+0xf
J org.eclipse.swt.internal.gtk.OS._Call(III)I
J org.eclipse.swt.internal.gtk.OS.Call(III)I
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
J org.eclipse.swt.internal.gtk.OS._Call(III)I
J org.eclipse.swt.internal.gtk.OS.Call(III)I
j org.eclipse.swt.widgets.Widget.fixedSizeAllocateProc(II)I+5
j org.eclipse.swt.widgets.Display.fixedSizeAllocateProc(II)I+17
Java_org_eclipse_swt_internal_gtk_OS__1CallJava Threads: ( => current thread )
0x0b4c1000 JavaThread "Worker-247" [_thread_blocked, id=25417, stack(0x741bc000,0x7420d000)]
0x0a300c00 JavaThread "Worker-246" [_thread_blocked, id=25235, stack(0x7d30c000,0x7d35d000)]
...
列出所有 Java 線程狀態(_thread_blocked、_thread_in_native 等),可檢查是否有死鎖、大量阻塞線程等異常模式。
VM state: not at safepoint (normal execution)
VM Mutex/Monitor currently owned by a thread: None
not at safepoint:崩潰發生於正常執行期,非 GC 或停頓階段Mutex/Monitor:JVM 內部鎖狀態,若有死鎖會顯示持有者Heap
PSYoungGen total 149056K, used 125317K [0xa9700000, 0xb41a0000, 0xb41a0000)
eden space 123520K, 95% used [0xa9700000,0xb0ac0de0,0xb0fa0000)
from space 25536K, 26% used [0xb28b0000,0xb2f50748,0xb41a0000)
to space 25600K, 0% used [0xb0fa0000,0xb0fa0000,0xb28a0000)
PSOldGen total 261248K, used 239964K [0x941a0000, 0xa40c0000, 0xa9700000)
object space 261248K, 91% used [0x941a0000,0xa2bf7018,0xa40c0000)
PSPermGen total 163328K, used 130819K [0x841a0000, 0x8e120000, 0x941a0000)
object space 163328K, 80% used [0x841a0000,0x8c160c40,0x8e120000)
Code Cache [0xb4262000, 0xb5ac2000, 0xb7262000)
total_blobs=5795 nmethods=5534 adapters=209 free_code_cache=25103616 largest_free_block=38336
JIT 編譯代碼緩存區,與永久代分離。關注 free_code_cache 與 largest_free_block,過小會導致 JIT 停止編譯,影響效能。
Dynamic libraries:
00101000-00122000 r-xp 00000000 08:01 3483560 /usr/lib/libjpeg.so.62.0.0
00122000-00123000 rwxp 00020000 08:01 3483560 /usr/lib/libjpeg.so.62.0.0
...
進程虛擬記憶體映射表。每行格式:起始-結束 權限 偏移 主設備號:次設備號 inode 路徑。用途:確認崩潰時載入哪些 Native 庫、版本是否正確、是否有衝突庫、堆/棧/守護頁位置。
VM Arguments:
jvm_args: -DOSgi.requiredJavaVersion=1.5 -XX:MaxPermSize=256m -Xms40m -Xmx512m ...
Java_command: /.../eclipse/plugins/org.eclipse.equinox.launcher_1.2.0.v20110502.jar ...
Environment Variables:
PATH=...
DISPLAY=:0.0
關鍵排查點:-Xmx/-Xms 堆大小、-XX:MaxPermSize 永久代大小、DISPLAY 圖形環境(SWT/GTK 依賴)。
Signal Handlers:
SIGSEGV: [libjvm.so+0x726440], sa_mask[0]=0x7ffbfeff, sa_flags=0x10000004
...
OS: Red Hat Enterprise Linux Client release 5.4 (Tikanga)
CPU: total 4 (4 cores per cpu, 1 threads per core) family 6 model 42 stepping 7
Memory: 4k page, physical 3631860k(155144k free), swap 5124724k(5056452k free)
libjvm.so 內)JDK 版本 + 庫名稱 + 錯誤特徵,如 JDK 6u32 libgtk crash-Xmx/MaxPermSizeulimit -c unlimited 並配合 gdb 分析 core 檔案可獲取更完整調用棧hs_err_pid.log 是 JVM 崩潰現場的「黑盒錄音器」。掌握其結構與關鍵欄位解讀方法,能將模糊的「程式掛了」轉化為具體的「GTK 庫在 SWT 呼叫下觸發空指標解引用」,進而制定精準修復方案。建議將日誌分析納入生產環境故障應急 SOP 中。