Java可执行命令之jmap
- 1️⃣ 概念
- 2️⃣ 优势和缺点
- 3️⃣ 使用
- 3.1 语法格式
- 3.2 生成堆转储文件
- 3.3 执行jmap命令查看内存使用情况
- 3.4 执行jmap命令打印对象统计信息
- 4️⃣ 应用场景
- 🌾 总结
1️⃣ 概念
jmap
是 Java Development Kit(JDK)
自带的一个工具,用于生成Java堆转储文件(Heap Dump
)。它的设计目的是为了帮助开发人员分析和调试Java应用程序在运行时产生的内存问题。
jmap
命令可以通过连接到运行中的Java进程,生成指定类型的Java堆转储文件。Java堆转储文件是应用程序在特定时间点的内存快照,记录了Java虚拟机中对象的详细信息、引用关系以及当前内存使用情况。
jmap
可以生成多种格式的Java堆转储文件,包括二进制格式(默认)、文本格式和HPROF
二进制格式,它支持在特定的进程ID下生成堆转储文件,也支持对远程虚拟机进行操作。
同时,jmap
还提供了一些额外的选项,如打印类加载器信息、查看共享对象映射等。
jmap
命令通过Java虚拟机提供的 HotSpot Diagnostic
接口,连接到正在运行的Java进程,并请求生成Java堆转储文件。它使用Java虚拟机的Heap Dumper
功能收集堆内对象的详细信息,并保存到指定的输出文件中。
2️⃣ 优势和缺点
优点:
- 提供了一种快速生成Java堆转储文件的方式,方便开发人员获取内存快照;
- 可以生成各种格式的堆转储文件,如二进制格式、文本格式等,满足不同需求;
- 在处理大型堆转储文件时,
jmap
的性能表现较好。
缺点:
jmap
需要连接到正在运行的Java进程,如果权限不足或者连接失败,可能无法使用该命令;- 处理大型堆转储文件时,可能会占用较多的系统资源,包括CPU和内存;
jmap
生成的堆转储文件可能过于庞大,需要额外的工具来分析和解读。
3️⃣ 使用
3.1 语法格式
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)(连接到远程调试服务器)
其中,[option]
是可选的一些命令参数选项,<pid>
是Java进程的进程ID。对于命令中可选参数汇总如下:
参数 | 说明 |
---|---|
<none> | 打印与Solaris pmap 相同的信息 |
-heap | 打印Java堆摘要信息 |
-histo[:live] | 打印Java堆对象的直方图;如果指定"live "子选项,则只计算存活对象 |
-clstats | 打印类加载器统计信息 |
-finalizerinfo | 打印等待终止的对象信息 |
-dump:<dump-options> | 以hprof 二进制格式导出Java堆。转储选项<dump-options> :live :仅转储活动对象;如果没有指定,堆中的所有对象都被转储;format=b 二进制格式; file=<file> 将堆转储到<file> 。示例: jmap-dump:live,format=b,file=heap.bin<pid> |
-F | 强制操作。与-dump:<dump-options> <pid> 或 -histo 一起使用,当不响应时强制执行堆转储或直方图。此模式不支持"live "子选项 |
-h | -help | 打印帮助信息 |
-J<flag> | 将参数直接传递给运行时系统 |
如果生成的堆转储文件过大,可以考虑使用压缩格式(如gzip
)进行存储,以减少其占用空间。对于大型堆转储文件,可以使用 jhat
或其他分析工具来进一步解读和分析。
3.2 生成堆转储文件
jmap -dump:format=b,file=heapdump.hprof <pid>
上述命令会生成一个二进制格式的Java堆转储文件。如下图所示:
3.3 执行jmap命令查看内存使用情况
jmap -heap <pid>
运行上述命令可以输出Java堆的内存使用情况摘要信息,包括堆配置、空闲和已使用空间等。输出结果:
Attaching to process ID 172832, 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 = 2099249152 (2002.0MB)
NewSize = 44040192 (42.0MB)
MaxNewSize = 699400192 (667.0MB)
OldSize = 88080384 (84.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 = 33554432 (32.0MB)
used = 4710360 (4.492149353027344MB)
free = 28844072 (27.507850646972656MB)
14.03796672821045% used
From Space:
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 = 88080384 (84.0MB)
used = 0 (0.0MB)
free = 88080384 (84.0MB)
0.0% used
3162 interned Strings occupying 259504 bytes.
这个执行结果显示了与Java堆配置和使用相关的信息。下面是对每个部分的解释:
Attaching to process ID 172832, please wait...
:正在连接到进程ID为172832的进程,请稍等…Debugger attached successfully.
:成功附加调试器。Server compiler detected.
:检测到服务器编译器。说明正在使用JVM的C2(客户端编译器)进行即时编译。JVM version is 25.202-b08
:JVM版本号为25.202-b08。
接下来是Java堆的配置信息:
using thread-local object allocation.
:使用线程本地对象分配。Parallel GC with 10 thread(s)
:采用并行GC(垃圾收集器),共有10个线程。
Heap Configuration 部分列出了Java堆的配置设置,包括以下目录:
MinHeapFreeRatio
:最小的可用于自由空间的堆比例。MaxHeapFreeRatio
:最大的可用于自由空间的堆比例。MaxHeapSize
:堆的最大大小。NewSize
:新生代的初始大小。MaxNewSize
:新生代的最大大小。OldSize
:老年代的初始大小。NewRatio
:新生代与老年代的比例。SurvivorRatio
:Eden区和Survivor区的比例。MetaspaceSize
:元空间(Metaspace)的初始大小。CompressedClassSpaceSize
:压缩类空间的大小。MaxMetaspaceSize
:元空间的最大大小。G1HeapRegionSize
:使用G1收集器时的堆区域大小。
Heap Usage 部分显示了Java堆的使用情况,包括各个区域的容量、已用空间和空闲空间:
PS Young Generation
:表示Parallel Scavenge GC中的新生代(Parallel Scavenge是一种垃圾收集器)Eden Space
:伊甸园区域的容量、已用空间和空闲空间。From Space
:幸存者(Survivor)区中的From区域的容量、已用空间和空闲空间。To Space
:幸存者(Survivor)区中的To区域的容量、已用空间和空闲空间。PS Old Generation
:表示Parallel Scavenge GC中的老年代。capacity
:容量。used
:已使用的空间。free
:可用的空闲空间。- 最后一行
3162 interned Strings occupying 259504 bytes.
:表示共有3162个interned字符串占用了259504字节的内存。
这些信息提供了有关Java堆配置和使用情况的详细数据,可用于分析和优化应用程序的内存使用。
3.4 执行jmap命令打印对象统计信息
jmap -histo <pid>
上述命令会输出Java堆中各个类的实例数目和内存占用情况,可以帮助开发人员了解应用程序的内存使用情况。输出结果:
num #instances #bytes class name
----------------------------------------------
1: 660 2093048 [I
2: 1185 1171784 [B
3: 7723 910880 [C
4: 5893 141432 java.lang.String
5: 691 78976 java.lang.Class
6: 1294 60888 [Ljava.lang.Object;
7: 791 31640 java.util.TreeMap$Entry
8: 628 25120 java.util.LinkedHashMap$Entry
9: 456 22144 [Ljava.lang.String;
10: 365 11680 java.util.HashMap$Node
11: 38 11584 [Ljava.util.HashMap$Node;
12: 152 10944 java.lang.reflect.Field
13: 435 10440 java.lang.StringBuilder
14: 242 7744 java.util.Hashtable$Entry
15: 233 7456 java.io.File
16: 101 6464 java.net.URL
17: 241 5784 java.lang.StringBuffer
18: 125 5000 java.lang.ref.SoftReference
19: 258 4128 java.lang.Integer
20: 115 3680 java.util.concurrent.ConcurrentHashMap$Node
21: 25 3648 [Ljava.util.Hashtable$Entry;
22: 72 3456 java.nio.HeapCharBuffer
23: 71 3408 java.nio.HeapByteBuffer
24: 42 3360 [S
25: 8 3008 java.lang.Thread
26: 5 2568 [J
27: 20 2496 [Ljava.util.concurrent.ConcurrentHashMap$Node;
28: 44 2464 sun.misc.URLClassPath$JarLoader
29: 2 2384 [[Ljava.lang.Object;
30: 89 2136 java.net.Parts
31: 2 2080 [[C
32: 26 2080 java.lang.reflect.Constructor
...
369: 1 16 sun.util.resources.LocaleData$LocaleDataResourceBundleControl
Total 23572 4710360
这个执行结果是一个对象直方图,列出了不同类的实例数量和占用的内存大小。下面是对每个列的解释:
num
:序号,表示第几行。#instances
:实例数量,表示内存中存在多少个该类的实例。#bytes
:内存大小,表示该类实例所占用的总字节数。class name
:类名,表示相应实例的类名。
接下来的表格显示了一系列对象的统计数据,从最多实例到最少实例进行排序。其中每一行对应一个类的统计信息。
例如,在第4行:
4: 5893 141432 java.lang.String
表示有5893个java.lang.String类的实例,占用141,432字节的内存。
最后一行 Total 23572 4710360
表示总共有23,572个对象实例,占用4,710,360字节的内存。
通过分析对象直方图,可以了解系统中不同类型的对象的创建情况和内存消耗,从而帮助开发人员找到内存相关的问题,并进行性能优化和内存管理。
4️⃣ 应用场景
- 分析Java应用程序的内存使用情况,包括堆大小、对象数量、内存泄漏等问题;
- 为内存相关的性能调优提供数据支持,比如查找常驻内存的对象、优化内存分配等;
- 在应用程序出现内存溢出或性能问题时,生成堆转储文件进行进一步分析和定位问题。
需要注意,jmap
需要操作系统级别的权限来连接到正在运行的Java进程,需要确保当前用户有足够的权限。在处理大型堆转储文件时,可能会占用较多的系统资源,请确保足够的CPU和内存。
而如果生成的堆转储文件非常庞大时,需要使用专门的工具(如 jhat
、MAT
等)进行解读和分析。
MAT(Memory Analyzer Tool)
是一个Java堆分析器,它是一款强大的开源工具,用于分析Java应用程序在运行时产生的内存问题。MAT
可以帮助开发人员快速定位和解决内存泄漏、大对象占用过多内存、内存溢出等常见的内存相关问题。
MAT
提供了多种功能和特性:
- 内存快照分析:可以加载并分析通过
jmap
或者其他工具生成的Java堆转储文件(如hprof
格式),以获取详细的内存使用情况。- 强大的查询和筛选功能:支持丰富的查询语言和过滤条件,方便开发人员查找特定类型的对象,快速定位问题所在。
- 可视化对象图:以直观的方式展示Java堆中的对象及其引用关系,帮助开发人员理解对象之间的关联,从而更好地排查内存问题。
- 内存报告和统计:生成详细的内存报告,包括对象数量、内存占用、GC根引用等统计信息,帮助开发人员分析对象的分布和趋势。
- 内存泄漏检测:自动检测可能造成内存泄漏的对象,识别存在潜在泄漏的代码路径,辅助开发人员修复内存问题。
- 快速分析和低内存占用:
MAT
具有高效的内存使用和分析性能,即使在处理大型堆转储文件时也能保持较低的内存占用。
🌾 总结
jmap
命令是Java开发工具包(JDK)中的一个有用工具,用于生成Java堆转储文件以及查看堆和对象统计信息。通过连接到运行中的Java进程,jmap
提供了快速生成内存快照的方式,帮助开发人员检测和调试Java应用程序的内存问题。然而,使用时需要注意权限、资源消耗以及处理生成的大型转储文件的需求。综上所述,jmap
是一个强大的工具,适用于各种Java内存分析和调优的场景。