背景介绍
jdk安装后会自带一些小工具,jmap命令(Memory Map for Java)是其中之一。主要用于打印指定Java进程(或核心文件、远程调试服务器)的共享对象内存映射或堆内存细节。
jmap命令可以获得运行中的jvm的堆的快照,从而可以离线分析堆,以检查内存泄漏,检查一些严重影响性能的大对象的创建,检查系统中什么对象最多,各种对象所占内存的大小等等。可以使用jmap生成Heap Dump。
如果不想使用jmap命令,要想获取Java堆转储快照还有一些比较“暴力”的手段:譬如在前面用过的 -XX:+HeapDumpOnOutOfMemoryError参数,可以让虚拟机在OOM异常出现之后自动生成dump文件,通过-XX:+HeapDumpOnCtrlBreak参数可以使用[ctrl]+[Break]键让虚拟机生成dump文件,又或者在Linux系统下通过Kill -3 命令发送进程退出信息“恐吓”一下虚拟机,也能拿到dump文件。
jmap的作用并不仅仅是为了获取dump文件,他还可以查询finalize执行队列,java堆和永久代的详细信息,如空间使用率、当前用的是哪种收集器等。
命令格式
C:\Users\kino>jmap
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
主要选项:
选项 | 作用 |
---|---|
-dump | 生成java堆转储快照,格式为:-dump:[live,]format=b,file=<filename>,其中live子参数说明是否只dump出存活对象 |
-finalizerinfo | 显示在F-Queue中等待Finalizer线程执行finalize方法的对象,只在linux/solaris平台下有效 |
-heap | 显示堆详细信息,如使用哪种回收期、参数配置、分带状况等,只在linux/solaris平台下有效 |
-histo | 显示堆中对象统计信息,包括类、实例数量和合计容量 |
-permstat | 以ClassLoader为统计口径显示永久代内存状况,只在linux/solaris平台下有效 |
-F | 当虚拟机进程对-dump选项没有响应时,可以使用这个选项强制生成dump快照,只在linux/solaris平台下有效 |
参数说明
jmap -dump:生成java堆转储快照
生成java对转存快照,格式:jmap -dump:[live,]format=b,file=文件名 <pid>
C:\Users\kino>jmap -dump:live,format=b,file=D:/1.hprof 26280
Dumping heap to D:\1.hprof ...
Heap dump file created
可以使用jdk提供的jvisualvm.exe查看hprof文件,文件——装入
jmap -heap:显示堆详细信息
显示堆详细信息
命令格式:jmap -heap <pid>
C:\Users\kino>jmap -heap 26280
Attaching to process ID 26280, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.202-b08
using thread-local object allocation.
Parallel GC with 10 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 4246732800 (4050.0MB)
NewSize = 88604672 (84.5MB)
MaxNewSize = 1415577600 (1350.0MB)
OldSize = 177733632 (169.5MB)
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 = 696254464 (664.0MB)
used = 560183024 (534.2321624755859MB)
free = 136071440 (129.76783752441406MB)
80.45665097523884% used
From Space:
capacity = 38273024 (36.5MB)
used = 0 (0.0MB)
free = 38273024 (36.5MB)
0.0% used
To Space:
capacity = 41943040 (40.0MB)
used = 0 (0.0MB)
free = 41943040 (40.0MB)
0.0% used
PS Old Generation
capacity = 364904448 (348.0MB)
used = 111581752 (106.41265106201172MB)
free = 253322696 (241.58734893798828MB)
30.578348006325207% used
39846 interned Strings occupying 4039512 bytes.
jmap -histo:显示堆中对象统计信息
显示堆中对象统计信息,包括类、实例数量和合计容量
命令格式:jmap -histo[:live] <pid>
C:\Users\kino>jmap -histo 26280
num #instances #bytes class name
----------------------------------------------
1: 2654443 595971784 [C
2: 13834 45925552 [I
3: 1610027 38640648 java.lang.String
4: 366673 14666920 java.util.LinkedHashMap$Entry
5: 248400 9936000 org.springframework.boot.devtools.filewatch.FileSnapshot
6: 294814 9434048 java.io.File
7: 107135 9427880 java.lang.reflect.Method
8: 50199 6990904 [Ljava.util.HashMap$Node;
9: 107073 6884568 [Ljava.lang.String;
10: 105708 6441048 [Ljava.lang.Object;
11: 155185 4965920 java.util.concurrent.ConcurrentHashMap$Node
12: 121191 3878112 java.util.HashMap$Node
13: 73628 3534144 org.aspectj.weaver.reflect.ShadowMatchImpl
14: 117849 2828376 java.util.ArrayList
15: 73628 2356096 org.aspectj.weaver.patterns.ExposedState
16: 47234 2031792 [Ljava.io.File;
17: 35823 2006088 java.util.LinkedHashMap
18: 40210 1930080 java.util.HashMap
.
.
.
.
.
6834: 1 16 sun.rmi.transport.DGCImpl_Stub
6835: 1 16 sun.rmi.transport.proxy.RMIDirectSocketFactory
6836: 1 16 sun.rmi.transport.tcp.TCPTransport$1
6837: 1 16 sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$71/931120364
6838: 1 16 sun.security.provider.NativeSeedGenerator
6839: 1 16 sun.security.util.ByteArrayLexOrder
6840: 1 16 sun.security.util.ByteArrayTagOrder
6841: 1 16 sun.text.normalizer.NormalizerBase$Mode
6842: 1 16 sun.text.normalizer.NormalizerBase$NFCMode
6843: 1 16 sun.text.normalizer.NormalizerBase$NFDMode
6844: 1 16 sun.text.normalizer.NormalizerBase$NFKCMode
6845: 1 16 sun.text.normalizer.NormalizerBase$NFKDMode
6846: 1 16 sun.util.calendar.Gregorian
6847: 1 16 sun.util.locale.provider.AuxLocaleProviderAdapter$NullProvider
6848: 1 16 sun.util.locale.provider.CalendarDataUtility$CalendarWeekParameterGetter
6849: 1 16 sun.util.locale.provider.SPILocaleProviderAdapter
6850: 1 16 sun.util.locale.provider.TimeZoneNameUtility$TimeZoneNameGetter
6851: 1 16 sun.util.resources.LocaleData
6852: 1 16 sun.util.resources.LocaleData$LocaleDataResourceBundleControl
Total 7255510 804288504
项目实践注意事项
权限问题
确保你有足够的权限来执行 jmap
命令,特别是在生产环境中,可能需要以 root 用户或具有相应权限的用户身份运行。
性能影响
生成堆转储文件是一个比较耗时的操作,可能会对 Java 进程的性能产生一定的影响,因此建议在非业务高峰期进行操作。
文件大小
堆转储文件可能会非常大,需要确保磁盘有足够的空间来存储该文件。
实现原理
jmap
工具主要基于 Java 虚拟机工具接口(Java Virtual Machine Tool Interface,简称 JVMTI)和服务性代理(Serviceability Agent,简称 SA)来实现。JVMTI 是一组丰富的编程接口,允许外部工具与 Java 虚拟机(JVM)进行交互,获取虚拟机的运行时信息;SA 则是基于 JVMTI 开发的一组库和工具,为开发者提供了更高级的功能,方便对 JVM 进行调试和分析。
核心技术之一:JVMTI
JVMTI 是 JVM 提供的一个 native 编程接口,它允许外部工具监控和控制 JVM 的行为。通过 JVMTI,jmap
可以获取以下信息:
- 堆内存信息:包括堆的大小、各个代(新生代、老年代等)的使用情况、对象的分布等。
- 对象信息:可以获取对象的类型、数量、占用内存大小等信息。
- 类加载信息:了解类的加载情况、类的数量等。
核心技术之二:服务性代理(SA)
SA 是 JVM 提供的一个高级调试工具,它基于 JVMTI 实现了更复杂的功能。jmap
在获取堆转储快照时,通常会借助 SA 来完成。SA 可以直接访问 JVM 的内部数据结构,将堆中的对象信息以二进制格式保存到文件中,生成堆转储文件(.hprof 文件)。