JVM分析利器
大家在学习JVM的时候知道有好多参数,另外在我们系统在出现问题的时候我们可以接触对JVM中堆使用情况和垃圾回收情况进行分析,同时在jvm调优的时候通过分析GC日志中吞吐量和停顿时间来不断优化,那么对上述指标分析我们除了有JVM的系统理论知识支撑外,还要借助比较优秀的分析利器帮助我们去分析。
JVM分析工具
1.jvm参数
1.1 -XX参数
a.Boolean类型
格式:-XX:[+-]<name> +或-表示启用或者禁用name属性
比如:-XX:+UseConcMarkSweepGC 表示启用CMS类型的垃圾回收器
-XX:+UseG1GC 表示启用G1类型的垃圾回收器
b.非Boolean类型
格式:-XX<name>=<value>表示name属性的值是value
比如:-XX:MaxGCPauseMillis=500
1.2 其他参数
-Xms1000等价于-XX:InitialHeapSize=1000
-Xmx1000等价于-XX:MaxHeapSize=1000
-Xss100等价于-XX:ThreadStackSize=100
1.3 设置参数方式
开发工具中设置比如IDEA,eclipse
运行jar包的时候:java -XX:+UseG1GC xxx.jar
web容器比如tomcat,可以在脚本中的进行设置
通过jinfo实时调整某个java进程的参数(参数只有被标记为manageable的flags可以被实时修改)
例子
(1)设置堆内存大小和参数打印
-Xmx100M -Xms100M -XX:+PrintFlagsFinal
(2)查询+PrintFlagsFinal的值
:=true
(3)查询堆内存大小MaxHeapSize
:= 104857600
1.4常用参数汇总
| 参数 | 含义 | 说明 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | -XX:CICompilerCount=3 | 最大并行编译数 | 如果设置大于1,虽然编译速度会提高,但是同样影响系 统稳定性,会增加JVM崩溃的可能 | | -XX:InitialHeapSize=100M | 初始化堆大小 | 简写-Xms100M | | -XX:MaxHeapSize=100M | 最大堆大小 | 简写-Xmx100M | | -XX:NewSize=20M | 设置年轻代的大小 | | | -XX:MaxNewSize=50M | 年轻代最大大小 | | | -XX:OldSize=50M | 设置老年代大小 | | | -XX:MetaspaceSize=50M | 设置方法区大小 | | | -XX:MaxMetaspaceSize=50M | 方法区最大大小 | | | -XX:+UseParallelGC | 使用UseParallelGC | 新生代,吞吐量优先 | | -XX:+UseParallelOldGC | 使用UseParallelOldGC | 老年代,吞吐量优先 | | -XX:+UseConcMarkSweepGC | 使用CMS | 老年代,停顿时间优先 | | -XX:+UseG1GC | 使用G1GC | 新生代,老年代,停顿时间优先 | | -XX:NewRatio | 新老生代的比值 | 比如-XX:Ratio=4,则表示新生代:老年代=1:4,也就是新 生代占整个堆内存的1/5 | | -XX:SurvivorRatio | 两个S区和Eden区的比值 | 比如-XX:SurvivorRatio=8,也就是(S0+S1):Eden=2:8, 也就是一个S占整个新生代的1/10 | | -XX:+HeapDumpOnOutOfMemoryError | 启动堆内存溢出打印 | 当JVM堆内存发生溢出时,也就是OOM,自动生成dump 文件 | | -XX:HeapDumpPath=heap.hprof | 指定堆内存溢出打印目录 | 表示在当前目录生成一个heap.hprof文件 | | XX:+PrintGCDetails - XX:+PrintGCTimeStamps - XX:+PrintGCDateStamps Xloggc:$CATALINA_HOME/logs/gc.log | 打印出GC日志 | 可以使用不同的垃圾收集器,对比查看GC情况 | | -Xss128k | 设置每个线程的堆栈大小 | 经验值是3000-5000最佳 | | -XX:MaxTenuringThreshold=6 | 提升年老代的最大临界值 | 默认值为 15 | | -XX:InitiatingHeapOccupancyPercent | 启动并发GC周期时堆内存使用占比 | G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆 的使用率,而不只是某一代内存的使用比. 值为 0 则表 示”一直执行GC循环”. 默认值为 45. | | -XX:G1HeapWastePercent | 允许的浪费堆空间的占比 | 默认是10%,如果并发标记可回收的空间小于10%,则不 会触发MixedGC。 | | -XX:MaxGCPauseMillis=200ms | G1最大停顿时间 | 暂停时间不能太小,太小的话就会导致出现G1跟不上垃 圾产生的速度。最终退化成Full GC。所以对这个参数的 调优是一个持续的过程,逐步调整到最佳状态。 | | -XX:ConcGCThreads=n | 并发垃圾收集器使用的线程数量 | 默认值随JVM运行的平台不同而不同 | | -XX:G1MixedGCLiveThresholdPercent=65 | 混合垃圾回收周期中要包括的旧区域设置 占用率阈值 | 默认占用率为 65% | | -XX:G1MixedGCCountTarget=8 | 设置标记周期完成后,对存活数据上限为 G1MixedGCLIveThresholdPercent 的旧 区域执行混合垃圾回收的目标次数 | 默认8次混合垃圾回收,混合回收的目标是要控制在此目 标次数以内 | | - XX:G1OldCSetRegionThresholdPercent=1 | 描述Mixed GC时,Old Region被加入到 CSet中 | 默认情况下,G1只把10%的Old Region加入到CSet中 |
其他常用的参数:
-XX:+CMSParallelInitialMarkEnabled表示在初始标记的多线程执行,减少STW;
-XX:+CMSScavengeBeforeRemark:在重新标记之前执行minorGC减少重新标记时间;
-XX:+CMSParallelRemarkEnabled:在重新标记的时候多线程执行,降低STW;
-XX:CMSInitiatingOccupancyFraction=92和-XX:+UseCMSInitiatingOccupancyOnly配套使用,如果不设置后者,jvm第一次会采用92%但是后续jvm会根据运行时采集的数据来进行GC周期,如果设置后者则jvm每次都会在92%的时候进行gc;
-XX:+PrintHeapAtGC:在每次GC前都要GC堆的概况输出
2.常用命令
2.1jps
查看java进程
2.2 info
实时查看jvm参数
jinfo -flag name PID 查看某个java进程的name属性的值
jinfo -flag MaxHeapSize PID
jinfo -flag UseG1GC PID
实时修改参数
参数只有被标记为manageable的flags可以被实时修改
jinfo -flag [+|-] PID
jinfo -flag = PID
2.3 jstat
查看虚拟机性能的统计信息「使用jstat摸清线上系统的JVM运行状况」
查看类装载信息
jstat -class PID 1000 10
查看垃圾收集信息
jstat -gc PID 1000 10
jstat -gccapacity PID:堆内存分析
jstat -gcnew PID:年轻代GC分析,这里的TT和MTT可以看到对象在年轻代存活的年龄和存活的最大年龄
jstat -gcnewcapacity PID:年轻代内存分析
jstat -gcold PID:老年代GC分析
jstat -gcoldcapacity PID:老年代内存分析
jstat -gcmetacapacity PID:元数据区内存分析
jstat -gc PID
S0C:这是From Survivor区的大小
S1C:这是To Survivor区的大小
S0U:这是From Survivor区当前使用的内存大小
S1U:这是To Survivor区当前使用的内存大小
EC:这是Eden区的大小
EU:这是Eden区当前使用的内存大小
OC:这是老年代的大小
OU:这是老年代当前使用的内存大小
MC:这是方法区(永久代、元数据区)的大小
MU:这是方法区(永久代、元数据区)的当前使用的内存大小
YGC:这是系统运行迄今为止的Young GC次数
YGCT:这是Young GC的耗时
FGC:这是系统运行迄今为止的Full GC次数
FGCT:这是Full GC的耗时
GCT:这是所有GC的总耗时
2.4 jstack
jstack能生成JVM当前时刻的线程快照,以此来定位线程出现长时间停顿的原因,最常见应用场景为:
- 查看线程间死锁
- 分析CPU过高原因
查看线程堆栈信息命令
jstack [-option] <pid>
| 指令 | 说明 | | ---------- | ------------------------------------------------------------ | | -F | 当jstack指令无响应时,强制打印一个堆栈信息 | | -m | 打印包含Java和C/C++帧的混合模式堆栈跟踪 | | -l | 打印关于锁的其他信息,比如拥有java.util.concurrent ownable同步器的列表 | | -h / -help | 打印帮助信息 |
cpu 100%了定位如下方法:
top -c . 输入P按照cpu使用率排序
top -Hp 进程id 输入P
jstack -l [PID] >/tmp/log.txt
printf "%x\n" 线程pid --> 把线程pid转换成16进制
jstack 进程pid | grep ‘16进制的线程pid’ -C5 --color -->打印进程的堆栈信息
或者 jstack <pid>|grep -A 10 <pid_16>
2.5 jmap
查看打印及dump出堆内存转储快照信息
项目启动参数设置
-XX:+PrintFlagsFinal -Xms300M -Xms300M
打印查看堆内存信息
jmap -heap PID
jmap -histo PID
dump出堆内存相关信息
手动生成dump文件
jmap -dump:format=b,file=heap.hprof PID
然后借助jhat工具查看:启动jhat加载堆转储文件,然后浏览器中访问
jhat dump.hprof -port 7000
项目启动时候参数设置发生内存溢出时候能够自动dump出该文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hrprof
注:模式堆内存溢出设置堆内存大小 -Xms20M -Xmx20M
关于dump出的文件怎们去分析,可以借助工具去分析如MAT,perfma
3.常用工具
3.1 jconsole
JDK自带的可视化监控工具
可以查看java应用程序运行概况,监控堆信息,永久区的使用
3.2 jvisualvm
可以i监控本地和远端java进程的cpu,类线程等
远程连接服务器监控远端java进程,需要在远端程序上配置
加入要分析远程java进程,以阿里云服务器tomcat为例子
1.需要修改tomcat中 bin/catalina.sh 这个文件
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -
Djava.rmi.server.hostname=31.100.39.63 -Dcom.sun.management.jmxremote.port=8998
-Dcom.sun.management.jmxremote.ssl=false -
Dcom.sun.management.jmxremote.authenticate=true -
Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access -
Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password"
2.在 ../conf 文件中添加两个文件jmxremote.access和jmxremote.password
jmxremote.access 文件
guest readonly
manager readwrite
jmxremote.password 文件
guest guest
manager manager
授予权限 : chmod 600 *jmxremot*
3.将连接服务器地址改为公网ip地址
hostname -i 查看输出情况
172.26.225.240 172.17.0.1
vim /etc/hosts
172.26.255.240 31.100.39.63
4.启动tomcat
5.查看tomcat启动日志及端口监听
tail -f ../logs/catalina.out
lsof -i tcp:8080
6.查看8998监听情况,可以发现多开了几个端口
lsof -i:8998 得到PID
netstat -antup | grep PID
3.3jmc工具
3.4 阿里arthas
github :https://github.com/alibaba/arthas
Arthas 是Alibaba开源的Java诊断工具,采用命令行交互模式,是排查jvm相关问题的利器
下载安装:
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
# 然后可以选择一个Java进程
print usage
java -jar arthas-boot.jar -h
常用命令
version:查看arthas版本号
help:查看命名帮助信息
cls:清空屏幕
session:查看当前会话信息
quit:退出arthas客户端
---
dashboard:当前进程的实时数据面板
thread:当前JVM的线程堆栈信息
jvm:查看当前JVM的信息
sysprop:查看JVM的系统属性
---
sc:查看JVM已经加载的类信息
dump:dump已经加载类的byte code到特定目录
jad:反编译指定已加载类的源码
---
monitor:方法执行监控
watch:方法执行数据观测
trace:方法内部调用路径,并输出方法路径上的每个节点上耗时
stack:输出当前方法被调用的调用路径
4.分析堆内存
4.1MAT工具
Java堆分析器,用于查找内存泄漏 Heap Dump,称为堆转储文件,是Java进程在某个时间内的快照 下载地址 :https://www.eclipse.org/mat/downloads.php
获取dump文件
手动dump
jmap -dump:format=b,file=heap.hprof PID
自动dump
--xx:+HeapDumpOnOutOfMemoryError -XX:+HeapDumpPath=heap.hprof
4.2 perfma在线工具
5 GC日志分析工具
获取GC日志
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps
-Xloggc:gc.log
5.1 在线
http://gceasy.io
5.2 GCViewer
分析GC日志的工具:
1.GCHisto http://java.net/projects/gchisto
直接点击gchisto.jar就可以运行,点add载入gc.log
统计了总共gc次数,youngGC次数,FullGC次数,次数的百分比,GC消耗的时间,百分比,平均消耗时间,消耗时间最小最大值等
2.GCLogViewer http://code.google.com/p/gclogviewer/
点击run.bat运行
整个过程gc情况的趋势图,还显示了gc类型,吞吐量,平均gc频率,内存变化趋势等
Tools里还能比较不同gc日志
6 jvm参数配置模版
如何在JVM内存溢出OOM时候自动dump内存快照?
设置JVM参数:
-XX:+HeapDumpOnOutOfMemoryError
-XX:+HeapDumpPath=/usr/local/app/oom
jvm参数中加入打印GC日志
-XX:+PrintGCDetails 打印详细的GC日志
-XX:+PrintGCTimeStamps 打印出来每次GC发生的事件
-Xloggc:gc.log 这个参数可以设置将gc日志写入一个磁盘文件
下面总结一下JVM参数模板:
-Xms4096M -Xmx4096M -Xmn3072M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSParallelInitialMarkEnabled -XX:+CMSScavengeBeforeRemark -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/app/oom