概述
jdk自带的jvm监控工具
Java自带了几个jvm监控工具,如jstat、jmap、jstack。
jstat
jstat是常见的线上jvm问题排查工具,jstat用法:
说明:
- lines: 使用interval参数,会在间隔指定时间后输出当前JVM内存的状态,这个参数是指定输出多少行后,再输出title,这样就不需要翻屏看这一列的title了。
- vmid: 虚拟机的pid
- interval:间隔多少时间后循环输出,不指定的话,就输出一次
- count:指定输出多少次
jstat -option选项
]# jstat -options
-class
-compiler
-gc
-gccapacity
-gccause
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-printcompilation
jstat -gc
间隔1s统计输出一次,共统计10次。
含义详解:
参数 | 描述 |
---|---|
S0C | 年轻代中第一个survivor(幸存区)的容量 (字节) |
S1C | 年轻代中第二个survivor(幸存区)的容量 (字节) |
S0U | 年轻代中第一个survivor(幸存区)目前已使用空间 (字节) |
S1U | 年轻代中第二个survivor(幸存区)目前已使用空间 (字节) |
EC | 年轻代中Eden(伊甸园)的容量 (字节) |
EU | 年轻代中Eden(伊甸园)目前已使用空间 (字节) |
OC | Old代的容量 (字节) |
OU | Old代目前已使用空间 (字节) |
PC | Perm(持久代)的容量 (字节) |
PU | Perm(持久代)目前已使用空间 (字节) |
YGC | 从应用程序启动到采样时年轻代中gc次数 |
YGCT | 从应用程序启动到采样时年轻代中gc所用时间(s) |
FGC | 从应用程序启动到采样时old代(全gc)gc次数 |
FGCT | 从应用程序启动到采样时old代(全gc)gc所用时间(s) |
GCT | 从应用程序启动到采样时gc用的总时间(s) |
jstat -gcutil
每隔lines显示title: jstat -gcutil -h<lines> pid interval
详细含义:
参数 | 描述 |
---|---|
S0 | 年轻代中第一个survivor(幸存区)已使用的占当前容量百分比 |
S1 | 年轻代中第二个survivor(幸存区)已使用的占当前容量百分比 |
E | 年轻代中Eden(伊甸园)已使用的占当前容量百分比 |
O | old代已使用的占当前容量百分比 |
P | perm代已使用的占当前容量百分比 |
YGC | 从应用程序启动到采样时年轻代中gc次数 |
YGCT | 从应用程序启动到采样时年轻代中gc所用时间(s) |
FGC | 从应用程序启动到采样时old代(全gc)gc次数 |
FGCT | 从应用程序启动到采样时old代(全gc)gc所用时间(s) |
GCT | 从应用程序启动到采样时gc用的总时间(s) |
jstat -gccapacity
参数 | 描述 |
---|---|
NGCMN | 年轻代(young)中初始化(最小)的大小 (字节) |
NGCMX | 年轻代(young)的最大容量 (字节) |
NGC | 年轻代(young)中当前的容量 (字节) |
S0C | 年轻代中第一个survivor(幸存区)的容量 (字节) |
S1C | 年轻代中第二个survivor(幸存区)的容量 (字节) |
EC | 年轻代中Eden(伊甸园)的容量 (字节) |
OGCMN | old代中初始化(最小)的大小 (字节) |
OGCMX | old代的最大容量 (字节) |
OGC | old代当前新生成的容量 (字节) |
OC | Old代的容量 (字节) |
PGCMN | perm代中初始化(最小)的大小 (字节) |
PGCMX | perm代的最大容量 (字节) |
PGC | perm代当前新生成的容量 (字节) |
PC | Perm(持久代)的容量 (字节) |
YGC | 从应用程序启动到采样时年轻代中gc次数 |
FGC | 从应用程序启动到采样时old代(全gc)gc次数 |
jmap
用法:
说明:
-F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效.
-h | -help 打印辅助信息
-J 传递参数给jmap启动的jvm.
jmap -heap pid
打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况.
Concurrent Mark-Sweep GC
using parallel threads in the new generation. //新生代采用的是并行线程处理方式
using thread-local object allocation.
Concurrent Mark-Sweep GC //同步并行垃圾回收
Heap Configuration: //堆配置情况
MinHeapFreeRatio = 40 //最小堆使用比例
MaxHeapFreeRatio = 70 //最大堆可用比例
MaxHeapSize = 2147483648 (2048.0MB) //最大堆空间大小
NewSize = 268435456 (256.0MB) //新生代分配大小
MaxNewSize = 268435456 (256.0MB) //最大可新生代分配大小
OldSize = 5439488 (5.1875MB) //老生代大小
NewRatio = 2 //新生代比例
SurvivorRatio = 8 //新生代与suvivor的比例
PermSize = 134217728 (128.0MB) //perm区大小
MaxPermSize = 134217728 (128.0MB) //最大可分配perm区大小
Heap Usage: //堆使用情况
New Generation (Eden + 1 Survivor Space): //新生代(伊甸区 + survior空间)
capacity = 241631232 (230.4375MB) //伊甸区容量
used = 77776272 (74.17323303222656MB) //已经使用大小
free = 163854960 (156.26426696777344MB) //剩余容量
32.188004570534986% used //使用比例
Eden Space: //伊甸区
capacity = 214827008 (204.875MB) //伊甸区容量
used = 74442288 (70.99369812011719MB) //伊甸区使用
free = 140384720 (133.8813018798828MB) //伊甸区当前剩余容量
34.65220164496263% used //伊甸区使用情况
From Space: //survior1区
capacity = 26804224 (25.5625MB) //survior1区容量
used = 3333984 (3.179534912109375MB) //surviror1区已使用情况
free = 23470240 (22.382965087890625MB) //surviror1区剩余容量
12.43827838477995% used //survior1区使用比例
To Space: //survior2 区
capacity = 26804224 (25.5625MB) //survior2区容量
used = 0 (0.0MB) //survior2区已使用情况
free = 26804224 (25.5625MB) //survior2区剩余容量
0.0% used // survior2区使用比例
concurrent mark-sweep generation: //老生代使用情况
capacity = 1879048192 (1792.0MB) //老生代容量
used = 30847928 (29.41887664794922MB) //老生代已使用容量
free = 1848200264 (1762.5811233520508MB) //老生代剩余容量
1.6416783843721663% used //老生代使用比例
Perm Generation: //perm区使用情况
capacity = 134217728 (128.0MB) //perm区容量
used = 47303016 (45.111671447753906MB) //perm区已使用容量
free = 86914712 (82.8883285522461MB) //perm区剩余容量
35.24349331855774% used //perm区使用比例
Parallel GC
using thread-local object allocation.
Parallel GC with 4 thread(s) //GC 方式
Heap Configuration: //堆内存初始化配置
MinHeapFreeRatio=40 //对应jvm启动参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40)
MaxHeapFreeRatio=70 //对应jvm启动参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70)
MaxHeapSize=512.0MB //对应jvm启动参数-XX:MaxHeapSize=设置JVM堆的最大大小
NewSize = 1.0MB //对应jvm启动参数-XX:NewSize=设置JVM堆的‘新生代’的默认大小
MaxNewSize =4095MB //对应jvm启动参数-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小
OldSize = 4.0MB //对应jvm启动参数-XX:OldSize=<value>:设置JVM堆的‘老生代’的大小
NewRatio = 8 //对应jvm启动参数-XX:NewRatio=:‘新生代’和‘老生代’的大小比率
SurvivorRatio = 8 //对应jvm启动参数-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值
PermSize= 16.0MB //对应jvm启动参数-XX:PermSize=<value>:设置JVM堆的‘永生代’的初始大小
MaxPermSize=64.0MB //对应jvm启动参数-XX:MaxPermSize=<value>:设置JVM堆的‘永生代’的最大大小
Heap Usage: //堆内存分步
PS Young Generation
Eden Space: //Eden区内存分布
capacity = 20381696 (19.4375MB) //Eden区总容量
used = 20370032 (19.426376342773438MB) //Eden区已使用
free = 11664 (0.0111236572265625MB) //Eden区剩余容量
99.94277218147106% used //Eden区使用比率
From Space: //其中一个Survivor区的内存分布
capacity = 8519680 (8.125MB)
used = 32768 (0.03125MB)
free = 8486912 (8.09375MB)
0.38461538461538464% used
To Space: //另一个Survivor区的内存分布
capacity = 9306112 (8.875MB)
used = 0 (0.0MB)
free = 9306112 (8.875MB)
0.0% used
PS Old Generation //当前的Old区内存分布
capacity = 366280704 (349.3125MB)
used = 322179848 (307.25464630126953MB)
free = 44100856 (42.05785369873047MB)
87.95982001825573% used
PS Perm Generation //当前的 “永生代” 内存分布
capacity = 32243712 (30.75MB)
used = 28918584 (27.57891082763672MB)
free = 3325128 (3.1710891723632812MB)
89.68751488662348% used
生成jvm dump快照
jmap -dump:format=b,file=/home/work/jinze/dump_26041_05231438.hprof ${pid} --> 生成二进制堆栈文件。
jmap -heap ${pid} --查看jvm堆栈内存占用情况
jmap -histo:live ${pid} | head -20 --查看jvm内存占用前20存活对象
jmap–histo
-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量。
]$ jmap -histo:live 14645 | head -10
num
#instances
#bytes
class name
----------------------------------------------
1:
901564
1777759440
[B
2:
112206
123401632
[J
3:
1462437
92280272
[C
4:
2182305
69833760
java.util.concurrent.atomic.LongAdder
5:
622976
68936400
[Ljava.lang.Object;
6:
1518179
48581728
java.util.HashMap$Node
7:
936736
44963328
java.util.HashMap
8:
960914
38436560
java.util.TreeMap$Entry
9:
1453265
34878360
java.lang.String
10:
1380194
33124656
org.elasticsearch.common.util.concurrent.ReleasableLock
jmap -permstat pid
-permstat 打印classload和jvm heap永久区的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来. jdk1.8后已移除。
jstack
jstack是jdk中自带的用于查看进程内线程栈的工具,很轻量易用,并且执行时不会对性能造成很大的影响。当程序出现死锁时,我们可以通过jstack打印线程栈找到问题。
jstack用法:
使用jstack定位问题
找出CPU消耗多的代码
如果程序cpu占用很高,我们需要找到问题并优化,可以配合top命令,找出最耗cpu的进程,从而找到相应代码解决问题。
1、先用jps找出程序pid,这里是23034
2、用top命令找出该进程最耗cpu的线程。
~]# top -Hp 23034
结果如下图
23046线程占了93.8的cpu,就是它。
3、将23046转成16进制。因为top里的pid是10进制,而jstack里是16进制,叫nid。
可以用printf命令转换:
~]# printf "%xn" 23046
得到 5a06
4、jstack出场
~]# jstack 23034 | grep 5a06
结果如下:
writeFileThread占用了最多的cpu资源。找到后,可以优化代码了。
使用jstack时,可能遇到下面的情况:
Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding
原因:
1、jstack报错:Unable to open socket file。是因为这个java进程的pid文件删除了。
2、从Java 6 update 21 引入的bug sunbug 7009828,在Java 6 update 25修复。
解决办法:
1 修改tmpwatch设置
排查对应的/tmp/hsperfdata_*的目录,让jvm自己来管理,保证jps,jstat等命令可用。
修改/etc/cron.daily/tmpwatch
/usr/sbin/tmpwatch "$flags" -x /tmp/hsperfdata_* -x /tmp/.X11-unix -x /tmp/.XIM-unix
-x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix 240 /tmp
2 java程序重启
3 由于jdk版本导致的问题,需要升级jdk版本
Thread Dump收集
jstack -l
<pid> > <file-path>
For Example:
jstack -l 37320 > /opt/tmp/threadDump.txt
堆分析工具
Memory Analyzer(MAT)
是一款Java堆分析工具,能够快速找到占用堆内存空间最多的对象,以便程序进行优化,减少内存消耗,定位可能的内存泄漏问题。
对于生产环境,dump出来的文件可能会超过16GB,自己的台式机或者笔记本的内存根本不够用。可以下载linux系统的MAT,然后在linux上进行分析。
配置mat的-Xmx大小
- 解压MemoryAnalyzer-*.x86_64.zip,然后修改mat的配置文件
打开MemoryAnalyzer.ini文件,修改-Xmx的值,取值根据hprof文件的大小
-startup
plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.700.v20180518-1200
-vmargs
-Xms40960m
-Xmx40960m
执行分析命令
./ParseHeapDump.sh ../today_heap_dump/jvm.hprof org.eclipse.mat.api:suspects
支持另外两种分析结果:
org.eclipse.mat.api:overview
org.eclipse.mat.api:top_components
后台分析,并记录执行日志
nohup ~/analysis/mat/ParseHeapDump.sh ./java_pid33461.hprof org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components & echo $! > pid
查看分析报告
在拿到结果后,只需要吧三个.zip
包传到本地,解压后,用浏览器打开网页即可。
应用程序分析
Visual VM的Profiler
可以查看到程序对CPU和内存的使用情况,如分析程序中执行次数最多最耗时的方法,占用内存空间最多的对象等等。
程序动态跟踪工具 BTrace
BTrace是一个开源的Java程序动态跟踪工具。它通过Hotspot虚拟机的HotSwap技术将跟踪的代码动态替换到被跟踪的Java程序内,以观察程序运行的细节。
这个功能在实际的生产环境中十分有意义,每当在线运行的系统出现问题时,通过使用BTrace,可以在不修改代码、不重启应用的情况下,动态的查看程序运行的细节,方便的对程序进行调试。
参考:
how-to-take-thread-dumps-7-options;
jstat用法;
Java jstack用法;
https://blog.csdn.net/zhaozheng7758/article/details/8623530;
最后
以上就是帅气枫叶为你收集整理的jvm问题排查工具Thread Dump收集的全部内容,希望文章能够帮你解决jvm问题排查工具Thread Dump收集所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复