JVM(性能监控/故障定位/OOM)
2021-02-23 15:39:23 10 举报
AI智能生成
JVM调优+GC参数调优
作者其他创作
大纲/内容
性能监控
常用工具/命令
jps:显示Java进程状况
-l:输出主类的全名,如果进程执行的是 JAR 包,则输出 JAR 路径
-v:查看虚拟机启动时显式指定的JVM参数列表
未被显示指定的可通过 jinfo -flag 查看
jstat:监视虚拟
机各种运行状态
机各种运行状态
-class:监视类加载、卸载数量、总空间以及类装载所耗费的时间
-gcutil:监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gcnew:监视新生代的垃圾收集情况
-gcold:监视老年代的垃圾收集情况
示例
jstat -gc 2764 250 20
每250毫秒查询一次进程2764垃圾收集状况,一共查询20次
jstat -gcutil 2764
查看2764进程各分区占比以及Minor GC和Full GC发生的次数和耗时
jinfo:实时查看和
调整JVM配置参数
调整JVM配置参数
查看JVM参数
jinfo -flag <name> PID
jinfo -flag MaxMetaspaceSize 18348
调整JVM参数
布尔类型的JVM参数
jinfo -flag [+|-]<name> PID
数字/字符串类型的JVM参数
jinfo -flag <name>=<value> PID
jmap:Java内存映像工具
用于生成堆转储快照(一般称为heap dump或dump文件)还可以查询finalize执行队列、
Java堆和方法区的详细信息,如空间使用率、当前用的是哪种收集器等
Java堆和方法区的详细信息,如空间使用率、当前用的是哪种收集器等
jmap -dump
生成Java堆转储快照
jmap -heap PID
显示Java堆详细信息,如使用哪种回收器、参数配置、分代状况等
jmap -histo:live PID
显示堆中对象统计信息,包括类、实例数量、合计容量
jhat:堆转储快照分析工具
jhat命令与jmap搭配使用,来分析jmap生成的堆转储快照
jstack:Java堆栈跟踪工具
用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者 javacore文件)
线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,目的是定位线程
出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等
出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等
jstack -l PID
查看线程堆栈
扩展
getAllStackTraces()
可视化故障处理工具
JConsole
一款基于JMX(Java Manage-ment Extensions)的可视化监视、管理工具
启动JConsole后,会自动搜索本机运行的所有JVM进程,相当于可视化的jps命令
“内存”页签的作用相当于可视化的jstat命令,用于监视被收集器管理的虚拟机内存的变化趋势
“线程”页签的功能相当于可视化的jstack命令,用于分析线程停顿的原因,比如死循环,锁等待
Java VisualVM
功能最强大的运行监视和故障处理程序之一,曾经是Oracle官方主力发展的虚拟机故障处理工具
它除了常规的运行监视、故障处理外,还将提供其他方面的能力,譬如性能分析(Profiling)
优势:对应用程序实际性能的影响也较小,使得它可以直接应用在生产环境中
jps、jinfo、jstat、jstack、jmap、jhat等多种功能于一体
在Profiler页签中,VisualVM提供了程序运行期间方法级的处理器执行时间分析以及内存分析(生产不用)
BTrace动态日志跟踪插件
JMC
Java Mission Control:可持续在线的监控工具,可用于生产环境
JHSDB
一款基于服务性代理(Serviceability Agent,SA)实现的进程外调试工具
ArtThas
阿里巴巴JVM调优工具
GC日志分析工具
GCEasy
GCViewer
故障定位
CPU
CPU 占用过高
先用 top 显示进程列表,找到占用率最高的 PID
再使用 top -Hp pid 找到占用最高的线程 tid
printf '%x\n' tid 将线程ID转换为16进制 (小写)
最后使用 jstack pid | grep tid -A60
频繁上下文切换
vmstat 2 3
每隔2秒打印一次CPU信息,共打印3次
cs:表示上下文切换次数(context switch)
pidstat -w pid
针对 pid 进行上下文切换监控
cswch/s:每秒自愿上下文切换(进程无法获取到可供执行的资源从而自愿发生上下文切换)
nvcswch/s:每秒非自愿上下文切换(进程时间片用完、被高优先级进程抢走、系统中断等发生的非自愿的场景)
内存
内存溢出
栈内存溢出
StackOverflowError
StackOverflowError
原因:线程请求栈的深度超过当前Java虚拟机栈的最大深度(默认大小是1M,1024KB)
代码举例
解决:检测是否有无穷递归、死循环,如果不是bug,可以通过调整虚拟机栈的大小来解决(-Xss2m)
堆内存溢出
OutOfMemory
OutOfMemory
原因:堆内存被用光,或者内存泄漏堆积导致
OOM
对象太多(Java heap space)
修复内存泄露,或使用 -Xmx 增加堆内存大小
代码举例
GC回收超时(GC overhead limit exceeded)
使用 -XX:-UseGCOverheadLimit 取消 GC 开销限制
本地内存不足(Direct buffer memory)
打印的堆栈跟踪信息,使用操作系统本地工具进行诊断
线程太多(unable to create new native thread)
减少虚拟机栈的大小或增大虚拟机占用比例
元空间内存不足(Metaspace)
使用-XX: MaxMetaSpaceSize 增加 metaspace 大小
内存泄漏
程序在申请内存后,无法释放已申请的内存空间
导致频繁 GC
jstat -gc pid 1000
每秒打印一次GC详细信息(C:容量|U:已使用)(E:Eden|O:Old|M:MetaSpace)
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
jstat -gcutil 1000 3
查看最近3次GC空间占比
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
使用 jmap 生成 堆转储 快照文件 jmap -histo:live pid
通过 MAT 查看 Histogram 图即可找出是哪块代码
查看线程信息
top -H -p pid
左上角显示Threads: 28 total,下面显示详细的线程信息
线程数
pstree -p 8379 | wc -l
ls /proc/8379/task | wc -l
ps hH p 8379 | wc -l
调优流程
调优阶段
上线前:根据需求(支撑多少QPS)进行JVM规划和预估调优(几台机器,多大内存,堆内存划分)
上线初期:根据日志优化JVM运行环境(解决慢、卡顿问题)
上线后期:解决JVM运行过程中出现的各种问题(OOM,逃逸分析,频繁 full gc)
调优指标
停顿时间
垃圾收集器做垃圾回收中断应用执行的时间
-XX:MaxGCPauseMillis:停顿时间(建议)
GC会尝试各种手段达到这个时间,比如减小年轻代
GC时间比例
GC时间占用程序运行时间的百分比:1/(1+n)
-XX:GCTimeRatio = n(默认值99)即 1% 时间用于垃圾收集
例如将 n=19 则垃圾收集时间为1/(1+19) 即 5% 时间用于垃圾收集
吞吐量
吞吐量=应用程序时间/(应用程序时间+垃圾收集时间) 即 1-1/(1+n)
调优参数
标准参数,-开头
通过 java 命令查看
常用参数
java -version
java -help
非标准参数
-X开头
通过 java -X more 查看
常用参数
-Xms200m -Xmx200m:最小堆和最大堆
-Xmn60m:新生代
-Xss1m:栈空间大小
扩展:为什么最小堆和最大堆设置一样大?
防止内存震荡(否则JVM会将堆内存进行扩容和缩容)
扩展和回缩需要大量的计算,影响程序的执行效率
-XX开头
通过 java -XX:+PrintFlagsFinal -version | more 命令查看
常用参数
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
GC调优
Parallel常用参数
-XX:SurvivorRatio:调整eden和surviovor区域的大小
-XX:PreTenureSizeThreshold:大对象到底多大
-XX:MaxTenuringThreshold:设置的是年龄阈值,默认15(对象被复制的次数)
-XX:+ParallelGCThreads:并行收集器的线程数,一般设置为和CPU核数相同(同样适用于CMS)
-XX:+UseAdaptiveSizePolicy:自动选择各区大小比例
CMS常用参数
-XX:+UseConcMarkSweepGC:启用CMS收集器
-XX:ParallelCMSThreads:CMS线程数量
-XX:CMSInitiatingOccupancyFraction
使用多少比例的老年代后开始CMS收集,默认是68%(近似值)
如果频繁发生SerialOld卡顿,应该调小(频繁CMS回收)
如果频繁发生SerialOld卡顿,应该调小(频繁CMS回收)
-XX:+UseCMSCompactAtFullCollection:在FGC时进行压缩
-XX:+CMSClassUnloadingEnabled
默认情况下GC是不回收PermGen的空间的(其名字也能反映这点)
这个选项就是启用清除PermGen的功能,删除不用的classes
这个选项就是启用清除PermGen的功能,删除不用的classes
-XX:CMSInitiatingPermOccupancyFraction
达到什么比例时进行Perm回收
-XX:GCTimeRatio
设置GC时间占用程序运行时间的百分比
-XX:MaxGCPauseMillis
停顿时间(建议)GC会尝试各种手段达到这个时间,比如减小年轻代
G1常用参数
-XX:+UseG1GC
-XX:MaxGCPauseMillis
建议值,G1会尝试调整Young区的块数来达到这个值
-XX:+GCPauseIntervalMillis
GC的间隔时间
-XX:+G1HeapRegionSize
分区大小,建议逐渐增大该值
-XX:G1NewSizePercent
新生代最小比例,默认为5%
-XX:G1MaxNewSizePercent
新生代最大比例,默认为60%
-XX:GCTimeRatio
GC时间建议比例,G1回根据这个值调整堆空间
-XX:ConcGCThreads
线程数量
-XX:InitiatingHeapOccupancyPercent
启动G1堆空间占用比例
日均百万交易系统
JVM堆栈大小设置?
JVM 调优,让其几乎不发生 Full GC?
线程死锁
四个必要条件
互斥、请求和保持、不可剥夺、环路等待
预防死锁
破坏四个必要条件中任意一个都可以
指定加锁顺序、设置超时时间
银行家算法
保证系统动态分配资源后不进入不安全状态
死锁检测工具
Jstack和Jconsole
手写死锁(伪代码)
0 条评论
下一页