jmap常用来查看jvm内存的使用情况。
一,jmap
1,jmap -dump
1.1,手动dump
jmap -dump命令将jvm内存使用情况以二进制形式保存到文件当中,通过jprofile或者jdk自带工具bin目录下jVisualVM查看。
使用方式如下:
// 所有对象
jmap -dump:format=b,file=<filename.hprof> <pid>
// 存活对象
jmap -dump:live,format=b,file=<filename.hprof> <pid>
选项 | 作用 |
---|---|
dump | 生成dump文件(Java堆转储快照),-dump:live只保存堆中的存活对象 |
-heap | 输出整个堆空间的详细信息,包括GC的使用、堆配置信息,以及内存的使用信息等 |
-histo | 输出堆空间中对象的统计信息:类、实例数量和合计容量,-histo:live只统计存活对象 |
-J | 传递参数给jmap启动的jvm |
-finalizerinfo | 显示在F-Queue中等待Finalizer线程执行finalize方法的对象,仅linux/solaris平台有效 |
-permstat | 以ClassLoader为统计口径输出永久代的内存状态信息,仅linux/solaris平台有效 |
-F | 当虚拟机进程对-dump选项没有任何响应时,强制生成dump文件 |
1.2,自动dump
要获取内存的dump文件,除了上述手动执行方式,还可以通过在启动程序时加命令行参数,在jvm oom之前把dump文件保存至指定文件。
需要配合另外一个指令文件的参数:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\study\log_hprof\gc.hprof
1.3,jvisualVM打开dump文件
可以看到堆内对象的大小排序,据此可以找出堆中的大对象,判断是否出现了内存泄漏,或者其他什么问题。
1.4,区别
自动dump和手动dump的区别在于手动dump可以服务器性能出现问题的时候使用,而自动dump一定出现oom才会dump,使用场景比较单一。
2,jmap -heap
查看jvm内存空间的统计信息,如下:
jmap -heap 3307
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 22413312 (21.375MB)
used = 19915896 (18.99327850341797MB)
free = 2497416 (2.3817214965820312MB)
88.8574432908443% used
Eden Space:
capacity = 19922944 (19.0MB)
used = 18848104 (17.974952697753906MB)
free = 1074840 (1.0250473022460938MB)
94.60501419870477% used
From Space:
capacity = 2490368 (2.375MB)
used = 1067792 (1.0183258056640625MB)
free = 1422576 (1.3566741943359375MB)
42.87687602796053% used
To Space:
capacity = 2490368 (2.375MB)
used = 0 (0.0MB)
free = 2490368 (2.375MB)
0.0% used
tenured generation:
capacity = 49659904 (47.359375MB)
used = 31271600 (29.822921752929688MB)
free = 18388304 (17.536453247070312MB)
62.97152729091059% used
3,jmap -histo
jmap -histo可以查看堆内存中的对象数量、内存占用大小,这部分内容在dump文件中也可以看到。
jmap -histo 3037 | head -n 10
结果:
num #instances #bytes class name
1: 4 13762624 [Lorg.apache.hadoop.util.LightWeightGSet$LinkedElement;
2: 17562 9074832 [B
3: 48224 4512896 [C
4: 6713 2721424 [I
5: 43512 1044288 java.lang.String
6: 7975 900664 java.lang.Class
7: 9301 715544 [Ljava.lang.Object;
4,总结
-
由于jmap将访问堆中的所有对象,为了保证在此过程中不被应用线程干扰,jmap需要借助安全点机制,让所有线程停留在不改变堆中数据的状态。也就是说,由jmap导出的堆快照必定是安全点位置的。这可能导致基于该堆快照的分析结果存在偏差。
-
举个例子,假设在编译生成的机器码中,某些对象的生命周期在两个安全点之间,那么:live选项将无法探知到这些对象。
-
另外,如果某个线程长时间无法跑到安全点,jmap将一直等下去。与前面讲的jstat则不同,垃圾回收器会主动将jstat所需要的摘要数据保存至固定位置之中,而jstat只需直接读取即可。
二,jstack
jstack(JVM Stack Trace):用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)。
线程快照就是当前虚拟机内指定进程的每一条线程正在执行的方法堆栈的集合。
生成线程快照的作用:可用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。这些都是导致线程长时间停顿的常见原因。当线程出现停顿时,就可以用jstack显示各个线程调用的堆栈情况。
在thread dump中,要留意下面几种状态
- 死锁,Deadlock(重点关注)
- 等待资源,Waiting on condition(重点关注)
- 等待获取监视器,Waiting on monitor entry(重点关注)
- 阻塞,Blocked(重点关注)
- 执行中,Runnable
- 暂停,Suspended
- 对象等待中,Object.wait() 或 TIMED_WAITING
- 停止,Parked
option参数 | 作用 |
---|---|
-F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-l | 除堆栈外,显示关于锁的附加信息 |
-m | 如果调用本地方法的话,可以显示C/C++的堆栈 |
使用方法:
jstack pid
jstack 77932
三,jcmd
一个综合性的命令,可以实现jmap、jstack、jstat、jps等命令的功能。
使用方法:
jcmd -l
相当于 jpsjcmd pid help
查看某个线程可以使用的命令jcmd pic param param
来自上一步jcmd pid help
的结果
1,jcmd -l
2,jcmd 3037 help
3, jcmd 3307 Thread.print
Thread.print来自于上一步的查找结果,相当于jstack的效果