JVM 的線程堆棧 dump 也稱 core dump,內容為文本,主要包含當時 JVM 的線程堆棧,堆 dump 也稱 heap dump,內容為二進制格式,主要包含當時 JVM 堆內存中的內容。由于各個操作系統、各個 JVM 實現不同,即使同一 JVM 實現,各個版本也有差異,本文描述的方法都基于 64 位 Linux 操作系統環境,Java 8 Oracle HotSpot JVM 實現。
堆棧和堆的內容在定位問題的時候,都是非常重要的信息。線程堆棧 dump 可以了解當時 JVM 中所有線程的運行情況,比如線程的狀態和當前正在運行的代碼行。堆 dump 可以了解當時堆的使用情況,各個類實例的數量及各個實例所占用的空間大小。
線程堆棧
使用 jstack
jstack 是 JDK 自帶的工具,用于 dump 指定進程 ID(PID)的 JVM 的線程堆棧信息。
# 打印堆棧信息到標準輸出 jstack PID
# 打印堆棧信息到標準輸出,會打印關于鎖的信息 jstack -l PID
強制打印堆棧信息到標準輸出,如果使用 jstack PID 沒有響應的情況下(此時 JVM 進程可能掛起),
加 -F 參數 jstack -F PID
使用 jcmd
jcmd 是 JDK 自帶的工具,用于向 JVM 進程發送命令,根據命令的不同,可以代替或部分代替 jstack、jmap 等。可以發送命令 Thread.print
來打印出 JVM 的線程堆棧信息。
# 下面的命令同等于 jstack PID
jcmd PID Thread.print
# 同等于 jstack -l PID
jcmd PID Thread.print -l
使用 kill -3
kill 可以向特定的進程發送信號(SIGNAL),缺省情況是發送終止(TERM) 的信號 ,即 kill PID 與 kill -15 PID 或 kill -TERM PID 是等價的。JVM 進程會監聽 QUIT 信號(其值為 3),當收到這個信號時,會打印出當時的線程堆棧和堆內存使用概要,相比 jstack,此時多了堆內存的使用概要情況。但 jstack 可以指定 -l 參數,打印鎖的信息。
kill -3 PID
# 或 kill -QUIT PID
堆
-XX:+HeapDumpOnOutOfMemoryError
添加 JVM 參數 -XX:+HeapDumpOnOutOfMemoryError 后,當發生 OOM(OutOfMemory)時,自動堆 dump。缺省情況下,JVM 會創建一個名稱為 java_pidPID.hprof 的堆 dump 文件在 JVM 的工作目錄下。但可以使用參數 -XX:HeapDumpPath=PATH 來指定 dump 文件的保存位置。
# JVM 發生 OOM 時,會自動在 /var/log/abc 目錄下產生堆 dump 文件 java_pidPID.hprof
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/abc/
jmap
jmap 也是 JDK 自帶的工具,主要用于獲取堆相關的信息。
堆 dump
# 將 JVM 的堆 dump 到指定文件,如果堆中對象較多,需要的時間會較長,子參數 format 只支持 b,
即二進制格式
jmap -dump:format=b,file=FILE_WITH_PATH
# 如果 JVM 進程未響應命令,可以加上參數 -F 嘗試
jmap -F -dump:format=b,file=FILE_WITH_PATH
# 可以只 dump 堆中的存活對象,加上 live 子參數,但使用 -F 時不支持 live
jmap -dump:live,format=b,file=FILE_WITH_PATH
獲取堆概要信息
# -heap 參數用于查看指定 JVM 進程的堆的信息,包括堆的各個參數的值,堆中新生代、年老代的內存大小、使用率等
jmap -heap PID
# 同樣,如果 JVM 進程未響應命令,可以加上參數 -F 嘗試
jmap -F -heap PID
一個實例輸出如下:
Attaching to process ID 68322, please wait

Debugger attached successfully.
Server compiler detected.
JVM version is 25.112-b16
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 268435456 (256.0MB)
NewSize = 8388608 (8.0MB)
MaxNewSize = 89128960 (85.0MB)
OldSize = 16777216 (16.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 41943040 (40.0MB)
used = 1701504 (1.6226806640625MB)
free = 40241536 (38.3773193359375MB)
4.05670166015625% used
From Space:
capacity = 4194304 (4.0MB)
used = 0 (0.0MB)
free = 4194304 (4.0MB)
0.0% used
To Space:
capacity = 5242880 (5.0MB)
used = 0 (0.0MB)
free = 5242880 (5.0MB)
0.0% used
PS Old Generation
capacity = 30408704 (29.0MB)
used = 12129856 (11.56793212890625MB)
free = 18278848 (17.43206787109375MB)
39.889421134159484% used
16658 interned Strings occupying 1428472 bytes.
獲取堆中的類實例統計
# 打印 JVM 堆中的類實例統計信息,以占用內存的大小排序,同樣,如果 JVM 未響應命令,也可以使用 -F 參數
jmap -histo PID
# 也可以只統計堆中的存活對象,加上 live 子參數,但使用 -F 時不支持 live
jmap -histo:live PID
使用 jcmd
# 等同 jmap -dump:live,format=b,file=FILE_WITH_PATH
jcmd PID GC.heap_dump FILE_WITH_PATH
# 等同 jmap -dump:format=b,file=FILE_WITH_PATH
jcmd PID GC.heap_dump -all FILE_WITH_PATH
# 等同 jmap -histo:live PID
jcmd PID GC.class_histogram
# 等同 jmap -histo PID
jcmd PID GC.class_histogram -all