jmap
(Java Memory Map)是 JDK 自带的工具,用于分析 Java 堆内存的分布和对象信息。以下是 jmap
命令的详细说明及代码案例:
一、核心用途
- 查看堆内存配置:堆内存各区(Eden、Survivor、Old Gen)的分配和使用情况。
- 生成堆转储快照(Heap Dump):将堆内存保存为
.hprof
文件,用于离线分析内存泄漏。 - 统计对象分布:显示堆中对象的类型、数量及占用内存大小。
- 类加载器统计:查看类加载器的存活对象信息。
二、命令语法
jmap [options] <pid>
-
<pid>
:目标 Java 进程的进程 ID(可通过jps
或ps -ef | grep java
获取)。 -
[options]
:常用参数如下:
参数 | 作用 |
---|---|
-heap | 打印堆内存配置信息(JDK 8 及之前可用) |
-histo[:live] | 统计堆中对象分布(live 仅统计存活对象,触发 Full GC) |
-dump:live,format=b,file=<file> | 生成堆转储文件(live 仅转存活对象) |
-clstats | 打印类加载器统计信息 |
-finalizerinfo | 显示等待执行 finalize() 方法的对象 |
三、关键场景及代码案例
1. 查看堆内存配置(JDK 8 及之前)
jmap -heap <pid>
输出示例:
Attaching to process ID 12345, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.291-b10
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0 # 堆最小空闲比例
MaxHeapFreeRatio = 100 # 堆最大空闲比例
MaxHeapSize = 2147483648 (2048.0MB) # 最大堆内存
NewSize = 44564480 (42.5MB) # 新生代初始大小
MaxNewSize = 715653120 (682.5MB) # 新生代最大大小
OldSize = 89522176 (85.375MB) # 老年代大小
NewRatio = 2 # 新生代:老年代 = 1:2
SurvivorRatio = 8 # Eden:Survivor = 8:1:1
MetaspaceSize = 21807104 (20.796875MB) # 元空间初始大小
CompressedClassSpaceSize = 1073741824 (1024.0MB) # 压缩类空间大小
G1HeapRegionSize = 0 (0.0MB) # G1 区域大小
Heap Usage:
PS Young Generation # 新生代使用情况
Eden Space:
capacity = 33554432 (32.0MB)
used = 16777216 (16.0MB)
free = 16777216 (16.0MB)
50.0% used
From Space: # Survivor 区
capacity = 5242880 (5.0MB)
used = 0 (0.0MB)
free = 5242880 (5.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 = 89522176 (85.375MB)
used = 0 (0.0MB)
free = 89522176 (85.375MB)
0.0% used
2. 统计对象分布(-histo
)
jmap -histo:live <pid> > heap_objects.log
输出示例:
num #instances #bytes class name
----------------------------------------------
1: 200000 200000000 [B # byte 数组
2: 100000 8000000 java.lang.String
3: 50000 4000000 java.util.HashMap$Node
4: 10000 160000 java.lang.Class
5: 5000 80000 java.util.concurrent.ConcurrentHashMap$Node
-
[B
:表示byte[]
数组,通常占用内存最多。 -
live
参数:触发 Full GC 后统计存活对象(生产环境慎用)。
3. 生成堆转储文件(-dump
)
jmap -dump:live,format=b,file=heapdump.hprof <pid>
-
heapdump.hprof
:生成的堆转储文件,可用工具(如 MAT、JVisualVM)分析。 - 适用场景:内存泄漏分析、大对象定位。
4. 查看类加载器统计(-clstats
)
jmap -clstats <pid>
输出示例:
ClassLoader Parent #Classes #Instances Bytes
====================================================================
sun/misc/Launcher$AppClassLoader null 500 20000 16MB
jdk/internal/loader/ClassLoaders$AppClassLoader null 300 15000 12MB
-
#Classes
:该类加载器加载的类数量。 -
#Instances
:该加载器创建的实例数。
四、注意事项
- 权限问题:执行
jmap
的用户需与启动 Java 进程的用户一致。 - 生产环境慎用
live
:-histo:live
和-dump:live
会触发 Full GC,可能导致应用短暂停顿。 - JDK 版本兼容性:JDK 9+ 中
-heap
参数已弃用,改用jhsdb jmap --heap <pid>
。
五、结合其他工具分析
- MAT(Memory Analyzer Tool):分析
.hprof
文件,定位内存泄漏。 - JVisualVM:实时监控堆内存,生成和分析堆转储。
- jstat:监控堆内存各区使用率(如
jstat -gcutil <pid> 1000
)。
通过 jmap
可以快速定位内存瓶颈,结合其他工具能更高效地解决 Java 内存问题