jvm性能优化工具
jdk提供给我们了很实用的工具来分析JVM的状态,线程以及配置,这些工具包含于jdk中,并且以java实现,是JVM性能优化必不可少的工具集,这些工具都在$JAVA_HOME/bin下
 jps、jinfo、jstack、jmap、jstat基本使用
jps、jinfo、jstack、jmap、jstat基本使用
 
先说下各个命令的作用
- jps : 查看虚拟机进程工具
- jinfo:查看虚拟机配置工具,需要进程id
- jstack:虚拟机线程快照工具 ,可以用来排查死锁,或线程长时间停滞的问题
- jmap:虚拟机堆快照工具,生成dump文件,用来与MAT工具混合使用
- jstat :收集虚拟机各方面运行数据
jps(jvm process status tool)
jps [options] [hostid]
| 配置 | 作用 | 
|---|---|
| -q | 忽略主类的名称,只输出pid | 
| -m | 输出启动类main函数的参数 | 
| -l | 输出主类名,如果进程执行的为jar,则输出jar路径 | 
| -v | 输出具体进程启动时jvm参数 | 
如不指定hostid,则默认当前主机,常用方式 jps -ml | jps -lv

jinfo ( configuration info for java )
- jinfo pid : 显示jvm系统属性与vm参数信息
- jinfo -flags pid : 显示jvm vm参数信息,如最大最小堆,默认堆,垃圾收集器参数
- jinfo -sysprops pid : 显示jvm系统属性
- jinfo -flag xxx pid : 显示特定vm参数值 jinfo -flag MaxHeapSize pid 输出pid的最大堆内存
jstack ( stack trace for java )
jstack [options]  pid| 配置项 | 作用 | 
| -f | 当正常输出请求不被响应时,强制输出线程栈堆,当Java进程负载较高的时候,可以加上该参数,强制dump线程快照 | 
| -l | 除线程栈堆外,显示关于锁的附加信息 | 
| -m | 如果调用本地方法的话,可以显示c/c++的栈堆 | 

jmap(memory map for java )
jmap [option] pid| 配置项 | 作用 | 
| -heap | 查看当前jvm heapdump与垃圾收集器的使用情况 | 
| -dump:format=b,file=filename.hprof pid | 转储堆快照,生成hprof文件到指定路径 | 
| -histo pid | 列出当前heap中对象状况,附字节码与java对象映射表 | 

Heap Configuration:                                    #堆配置情况,也就是JVM参数配置的结果MinHeapFreeRatio         = 0                        #最小堆使用比例MaxHeapFreeRatio         = 100                      #最大堆可用比例MaxHeapSize              = 8522825728 (8128.0MB)    #最大堆空间大小NewSize                  = 177209344 (169.0MB)      #新生代分配大小MaxNewSize               = 2840592384 (2709.0MB)    #最大可新生代分配大小OldSize                  = 355467264 (339.0MB)      #老年代大小NewRatio                 = 2                        #新生代比例SurvivorRatio            = 8                        #新生代与suvivor的比例MetaspaceSize            = 21807104 (20.796875MB)   #元空间大小CompressedClassSpaceSize = 1073741824 (1024.0MB)    #压缩类空间大小MaxMetaspaceSize         = 17592186044415 MB        #最大元空间大小G1HeapRegionSize         = 0 (0.0MB)                #G1的region大小Heap Usage:                                            #堆使用情况
PS Young Generation                                    #新生代(Eden区 + survior(from + to)区)
Eden Space:                                            #Eden区capacity = 1928855552 (1839.5MB)                    #Eden区容量used     = 267720912 (255.3185577392578MB)          #已经使用大小free     = 1661134640 (1584.1814422607422MB)        #剩余容量13.87978025220211% used                             #使用比例
From Space:                                            #survior0区capacity = 66060288 (63.0MB)                        #survior0区容量used     = 0 (0.0MB)                                #survior0已经使用大小free     = 66060288 (63.0MB)                        #survior0剩余容量0.0% used                                           #survior0使用比例
To Space:                                              #survior1区capacity = 85983232 (82.0MB)                        #survior1区容量used     = 0 (0.0MB)                                #survior1已经使用大小free     = 85983232 (82.0MB)                        #survior1剩余容量0.0% used                                           #survior1使用比例
PS Old Generation                                      #老年代使用情况capacity = 695730176 (663.5MB)                      #老年代容量used     = 207137472 (197.54168701171875MB)         #老年代已使用大小free     = 488592704 (465.95831298828125MB)         #老年代剩余大小29.77267324969386% used                             #老年代使用比例jmap -histo:live pid 显示堆中对象的统计信息,如果指定了live子选项,则只计算活动的对象

jmap -dump:format=b,file=heapdump.hprof pid,dump当前内存快照,以hprof二进制格式转储Java堆到指定filename的文件中,live子选项是可选的


可以通过MT工具或者jdk自带的jvisualvm装载dump文件分析问题,
-XX:+HeapDumpOnOutOfMemoryError配置这玩意之后,oom的时候会自动jump的,到时候拿快照分析一波就好了
jstat ( jvm statistics monitoring tool)
jstat -< option > [-t] [-h] pid [< interval > [< count >]]
- -t 参数可以在输出信息前面加上一个 Timestamp 列,显示程序运行的时间
- -h 参数可以周期数据输出时,输出多少行后,跟着输出一个表头信息
- interval 表示循环时间间隔,默认单位为ms,可以在直接使用s/ms指定单位,如 60ms/1s, count 表示输出几次 ,下面是查询每10s 查询20次gc情况
jstat gc pid 10s 20  | 配置项 | 作用 | 
| -class | 监视类装载、卸载数量、总空间以及类装载所耗费的时间 | 
| -gc | 监视Java堆,包括Eden区、两survivor区、老年代、永久代等的容量、已用空间、GC时间合计等 | 
| -gccapacity | 与-gc基本相同,但关注点为Java堆各个区域使用到的最大、最小空间 | 
| -gcutil | 与-gc基本相同,但关注点为Java堆各个区域已使用空间占总空间的百分比 | 
| -gccause | 与-gcutil功能相同,但会额外输出导致上一次GC产生的原因 | 
| -gcnew | 监控新生代GC情况 | 
| -gcnewcapacity | 与-gcnew基本相同,但关注最大,最小空间 | 
| -gcold | 监控老年代GC情况 | 
| gcoldcapacity | 与-gcold基本相同,但关注最大,最小空间 | 
| -compiler | 输出被JIT编译过的方法、耗时等信息 | 
| -printcomplilation | 输出已经被JIT编译的方法 | 
查询gc情况 jstat -gc pid ,属性含义后缀是C代表容量,后缀是U代表已使用,后缀是T代表的是时间(秒)

| 属性 | 含义 | 
| S0C | 新生代survivor0容量 | 
| S1C | 新生代survivor1容量 | 
| S0U | 新生代survivor0已使用大小 | 
| S1U | 新生代survivor1已使用大小 | 
| EC | 新生代eden区容量 | 
| OC | 老年代容量 | 
| OU | 老年代已使用大小 | 
| MC | 元数据容量即方法区容量 | 
| MU | 元数据已使用空间 | 
| CCSC | 压缩类空间大小 | 
| CCSU | 压缩类空间使用大小 | 
| YGC | 新生代gc次数(young gc) | 
| YGCT | 新生代gc时间(s) | 
| FGC | 老生代gc次数(full gc) | 
| GCT | 总的gc时间,包括young gc和full gc | 
jstat -gccapacity pid 查看各空间容量

| 属性 | 含义 | 
| NGCMN | 新生代最小容量 | 
| NGCMX | 新生代最大容量 | 
| NGC | 当前新生代容量 | 
| S0C | survivor0大小 | 
| S1C | survivor1大小 | 
| EC | Eden区大小 | 
| OGCMN | 老年代最小容量 | 
| OGCMX | 老年代最大容量 | 
| OGC | 当前老年代大小 | 
| MCMN | 元数据最小容量 | 
| MCMX | 元数据最大容量 | 
| CCSMN | 最小压缩类空间大小 | 
| CCSMX | 最大压缩类空间大小 | 
| CCSC | 当前压缩类空间大小 | 
可视化工具jvisualvm和jconsole控制台
这两种方式都能可视化监控java程序的运行状态,不过VisualVm界面更美观,数据更实时,所以推荐使用VisUalVm
jvisualvm
命令行窗口输入jvisualvm,即可打开visualvm,可以查看本地java进程和远程java进程,支持导入dump文件


jconsole
命令行窗口输入jconsole,打开jconsole工具,可以查看java程序线程,内存、堆等信息


JVM问题排查步骤
1、top命令找到占用线程最高的进程
top
2、进入线程模式查找过高的线程pid
top -Hp  获取占用cpu过高的线程pid(1)中的pid
3、线程pid转换为十六进制
printf "%x\n" 占用最高的线程pid (2)中的pid

4、使用命令jstack pid| grep 0x16进制pid -A30 找到占用cpu资源过高的代码

因为我这是tomcat进程,所以没有定位到代码 ,正常情况会定位到代码栈信息,就可以定位问题啦

