jmap(Memory Map for Java) 命令用于生成堆转储快照(一般称为 heapdump 或 dump 文件)。目前获取 Java 堆转储快照的方式有以下几种:
使用
-XX:+HeapDumpOnOutOfMemoryError
参数让 Java 虚拟机在出行 OOM 之后自动生成 dump 文件。如下面测试程序:import java.util.ArrayList; import java.util.List; public class JMapOom { private static final int _1M = 1024 * 1024; public static void main(String[] args) throws InterruptedException { List<Byte[]> list = new ArrayList<>(); while (true) { list.add(new Byte[_1M]); Thread.sleep(1000); } } }
使用命令
java -XX:+HeapDumpOnOutOfMemoryError -Xmx20m JMapOom
运行上面代码,很快就会出现 oom 并自动生成 dump 文件:java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid9661.hprof ... Heap dump file created [34443383 bytes in 0.068 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at JMapOom.main(JMapOom.java:10)
使用
-XX:+HeapDumpOnCtrlBreak
( 1.4.2_12 或 1.5.0_14 及更高版本,且 1.6 之前的版本) 参数然后用 Ctrl+Break 键让虚拟机生成 dump 文件在 linux 系统下使用
kill -3
命令发出进程退出信号,拿到 dump 文件,如我们先用命令java -Xmx200m JMapOom
(这里把内存设置大些为了避免程序过早由于内存不足自动退出),然后我们找到其进程号,执行kill -3 pid
,看下控制台:2018-04-24 15:28:08 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.152-b16 mixed mode): "Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00007fc9100e5000 nid=0x2717 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C1 CompilerThread3" #8 daemon prio=9 os_prio=0 tid=0x00007fc9100c7800 nid=0x2716 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007fc9100c5800 nid=0x2715 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007fc9100c3800 nid=0x2714 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007fc9100c0800 nid=0x2713 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007fc9100bf000 nid=0x2712 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007fc91008c000 nid=0x2711 in Object.wait() [0x00007fc8f97ff000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000ff0084f0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143) - locked <0x00000000ff0084f0> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209) "Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007fc910087800 nid=0x2710 in Object.wait() [0x00007fc8f9900000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000ff000720> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x00000000ff000720> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) "main" #1 prio=5 os_prio=0 tid=0x00007fc910009000 nid=0x2706 waiting on condition [0x00007fc916d51000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at JMapOom.main(JMapOom.java:11) "VM Thread" os_prio=0 tid=0x00007fc91007f800 nid=0x270f runnable "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007fc91001e800 nid=0x2707 runnable "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007fc910020000 nid=0x2708 runnable "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007fc910022000 nid=0x2709 runnable "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007fc910024000 nid=0x270a runnable "GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00007fc910025800 nid=0x270b runnable "GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00007fc910027800 nid=0x270c runnable "GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00007fc910029000 nid=0x270d runnable "GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00007fc91002b000 nid=0x270e runnable "VM Periodic Task Thread" os_prio=0 tid=0x00007fc9100ea000 nid=0x2718 waiting on condition JNI global references: 6 Heap PSYoungGen total 59904K, used 18927K [0x00000000fbd80000, 0x0000000100000000, 0x0000000100000000) eden space 51712K, 27% used [0x00000000fbd80000,0x00000000fcb7fef8,0x00000000ff000000) from space 8192K, 56% used [0x00000000ff000000,0x00000000ff47c020,0x00000000ff800000) to space 8192K, 0% used [0x00000000ff800000,0x00000000ff800000,0x0000000100000000) ParOldGen total 136704K, used 45064K [0x00000000f3800000, 0x00000000fbd80000, 0x00000000fbd80000) object space 136704K, 32% used [0x00000000f3800000,0x00000000f64020b0,0x00000000fbd80000) Metaspace used 2626K, capacity 4486K, committed 4864K, reserved 1056768K class space used 286K, capacity 386K, committed 512K, reserved 1048576K
jmap 的作用并不仅仅是为了获取 dump 文件,它还可以查询 finalize 执行队列、Java 堆和永久代的详细信息,如空间使用率、当前用的是哪种收集器等。
使用 jmap -help
查看 jmap 的使用说明:
[root@localhost ~]# jmap -help
Usage:
jmap [option] <pid>
(to connect to running process)
jmap [option] <executable <core>
(to connect to a core file)
jmap [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server)
where <option> is one of:
<none> to print same info as Solaris pmap
-heap to print java heap summary
-histo[:live] to print histogram of java object heap; if the "live"
suboption is specified, only count live objects
-clstats to print class loader statistics
-finalizerinfo to print information on objects awaiting finalization
-dump:<dump-options> to dump java heap in hprof binary format
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file=<file> dump heap to <file>
Example: jmap -dump:live,format=b,file=heap.bin <pid>
-F force. Use with -dump:<dump-options> <pid> or -histo
to force a heap dump or histogram when <pid> does not
respond. The "live" suboption is not supported
in this mode.
-h | -help to print this help message
-J<flag> to pass <flag> directly to the runtime system
下面是命令选项的说明:
选项 | 说明 |
---|---|
<none> | 打印与 Solaris pmap 相同的信息 |
-heap | 显示 Java 堆的详细信息,如使用哪种回收期、参数配置、分代状况等。只在 Linux/Solaris 平台下有效 |
-histo[:live] | 显示堆中对象统计信息,包括类、实例数量、合计容量 |
-clstats | 打印类加载器的统计信息 |
-finalizerinfo | 显示在 F-Queue 中等待 Finalizer 线程执行 finalize 方法的对象。只在 Linux/Solaris 平台下有效 |
-dump:<dump-options> | 生成 Java 堆转储快照,格式为: -dump:[live,]format=b,file=<:filename>,其中 live 子参数说明是否只 dump 出存活的对象 |
-F | 当虚拟机进程对 -dump 选项没有响应时,可使用这个选项强制生成 dump 快照。只在 Linux/Solaris 平台下有效 |
-h/help | 显示命令帮助信息 |
-J<flag> | 传递参数给 jmap 启动的 jvm |
文章摘自《深入理解Java虚拟机》第二版 周志明著,仅作为学习记录,书籍中用到的案例代码及描述有部分修改,但未改变原意。