JVM调优参数与工具
活跃对象标记方法
GC Root对象与可达性分析
哪些是GC Root对象?
- 虚拟机堆栈局部变量对象引用
- 常量池对象引用
- 静态常量对象引用
- 本地方法引用的变量
GC收集器
JVM运行时内存结构
开启JMX远程管理
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.port=5000
常用JVM调优参数
GC日志
- -XX:+PrintGC
开启简单GC日志模式
简单模式的GC日志格式是与GC算法无关的,日志也没有提供太多的信息 - -XX:PrintGCDetails
开启详细GC日志模式 - -XX:+PrintGCTimeStamps和-XX:+PrintGCDateStamps
GC添加绝对的日期和时间
-Xloggc
GC日志输出到指定文件 - 可管理的JVM参数
可以使用JDK自带的jinfo工具来设置这些参数,或者是通过JMX客户端调用HotSpotDiagnostic MXBean的setVMOption方法来设置这些参数
参数分类和即时(JIT)编译器诊断
- -XX:+PrintCompilation 输出字节码转换成本地代码的编译过程
- -XX:+CITime JVM关闭时输出编译统计信息
- -XX:+UnlockExperimentalVMOptions 解锁实验性的非标准参数
内存调优
- -Xms and -Xmx (or: -XX:InitialHeapSize and -XX:MaxHeapSize)
设置最大最小堆内存大小
将最大和最小设置为相同值可以避免运行时动态内存分配带来的性能影响 - -XX:+HeapDumpOnOutOfMemoryError and -XX:HeapDumpPath
当发生内存溢出时自动的生成堆内存快照 和 路径, 默认为 JVM启动目录下的 java_pid.hprof
由于对内存可能很大,建议将路径设置到空间的地方 - -XX:OnOutOfMemoryError
设置内存溢出时的指令
例如执行 shell 脚本 - -XX:PermSize and -XX:MaxPermSize
设置永久代内存大小的初始和最大值
永久代用于存大对象,Class对象,常量数据等
JDK8已移除 - -XX:InitialCodeCacheSize and -XX:ReservedCodeCacheSize
设置代码缓存内存大小
代码缓存是字节码编译的本地代码的存储区域 - -XX:+UseCodeCacheFlushing
用于清理一部分代码缓存,避免代码缓冲区溢出
如果代码缓存被占满,JVM会打印出一条警告消息,并切换到interpreted-only 模式:JIT编译器被停用,字节码将不再会被编译成机器码。因此,应用程序将继续运行,但运行速度会降低一个数量级,直到有人注意到这个问题。
新生代垃圾回收
- -XX:NewSize and -XX:MaxNewSize
设置新生代大小
-XX:MaxNewSize <= -Xmx/2 - -XX:NewRatio
新生代和老年代比值
同时指定比值和大小,优先取大小 - -XX:SurvivorRatio
指定新生代中 Eden与Servivo 比值
幸存区过小会导致对象过早的被分配到老年代
反之,如果Eden过小会导致很快发生内存不足,导致新生代频繁GC - -XX:+PrintTenuringDistribution
指定JVM 在每次新生代GC时,输出幸存区中对象的年龄分布 - -XX:InitialTenuringThreshold, -XX:MaxTenuringThreshold and -XX:TargetSurvivorRatio
-XX:InitialTenuringThreshold 和 -XX:MaxTenuringThreshold 可以设定老年代阀值的初始值和最大值
参数 -XX:TargetSurvivorRatio 设定幸存区的目标使用率
新生代行为情况
从年龄分布中发现,有很多对象的年龄持续增长表明老年代阀值设置过大
如果幸存区很多对象年龄不大于1,则查看幸存区的目标使用率是否过小,导致对象都被移动到了老年代 - -XX:+NeverTenure and -XX:+AlwaysTenure
设置不使用老年代
设置不使用新生代
吞吐量收集器
- GC评估
吞吐量越高越好=>程序线程用时占比总用时
停顿时间越短越好=>应用线程因为GC而暂停 - -XX:+UseSerialGC
使用单线程串行面向吞吐量的GC收集器
该标志被推荐用于只有单个可用处理器核心的JVM - -XX:+UseParallelGC
使用多线程并行执行新生代垃圾收集 - -XX:+UseParallelOldGC
使用多线程的并行新生代和年老代gc收集器
通过并行执行来提高吞吐量 - -XX:ParallelGCThreads
指定并行GC线程数 - -XX:+UseAdaptiveSizePolicy
激活使用自适应的GC收集器配置
默认激活 - -XX:GCTimeRatio
指定GC吞吐量的目标值
通过-XX:GCTimeRatio=9我们要求应用程序线程在整个执行时间中至少9/10是活动的(因此,GC线程占用其余1/10)
-XX:GCTimeRatio的默认值是99,也就是说,应用程序线程应该运行至少99%的总执行时间 - -XX:MaxGCPauseMillis
JVM最大暂停时间的目标值(以毫秒为单位)
默认未设置
CMS收集器
- 并发标记清理收集器
低应用停顿时间
无碎片整理 - CMS收集器的GC周期由6个阶段组成
1.初始标记
2.并发标记
3.并发预清理
4.重标记
5.并发清理
6.并发重置 - -XX:+UseConcMarkSweepGC
激活CMS收集器。默认HotSpot JVM使用的是并行收集器 - -XX:UseParNewGC
当使用CMS收集器时,该标志激活年轻代使用多线程并行执行垃圾回收
使用-XX:+UseConcMarkSweepGC时,-XX:UseParNewGC会自动开启 - -XX:+CMSConcurrentMTEnabled
当该标志被启用时,并发的CMS阶段将以多线程执行(因此,多个GC线程会与所有的应用程序线程并行工作)。该标志已经默认开启,如果顺序执行更好,这取决于所使用的硬件,多线程执行可以通过-XX:-CMSConcurremntMTEnabled禁用。 - -XX:ConcGCThreads
定义并发CMS过程运行时的线程数 - -XX:CMSInitiatingOccupancyFraction
- -XX:+UseCMSInitiatingOccupancyOnly
标志用来命令JVM不基于运行时收集的数据来启动CMS垃圾收集周期 - -XX:+CMSClassUnloadingEnabled
开启永久代垃圾回收 - -XX:+CMSIncrementalMode
该标志将开启CMS收集器的增量模式。增量模式经常暂停CMS过程,以便对应用程序线程作出完全的让步 - -XX:+ExplicitGCInvokesConcurrent and -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
-XX:+ExplicitGCInvokesConcurrent命令JVM无论什么时候调用系统GC,都执行CMS GC,而不是Full GC
-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses保证当有系统GC调用时,永久代也被包括进CMS垃圾回收的范围内
当使用CMS收集器时,系统GC将是一件很不幸的事,因为它默认会触发一次Full GC - -XX:+DisableExplicitGC
该标志将告诉JVM完全忽略系统的GC调用(不管使用的收集器是什么类型)
JVM可视化分析工具
jvisualvm
JVM信息,可视化内存,CPU,线程,JMX,GC
jconsole
JVM信息,可视化内存,CPU,线程,JMX,GC
Eclipse Memory Analyzer
常用Linux指令
JVM工具
- jstack: 查看线程堆栈dump,排查死锁,阻塞
- jmap: 内存统计,dump,可以分析内存对象占比,引用情况
- jstat: GC统计,新生代,老年代GC,次数,占比
- jmc: 可以详细的分析,JVM资源使用情况,热点线程,热点方法等
60秒的飞行器记录,输出到 /tmp 目录
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,repository=/tmp,maxage=6h,settings=default APP
vmstat 查看机器综合信息
每秒采样一次,查看线程上下文切换,磁盘I/O,Net I/O等
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
4 0 0 2430836 306248 16904808 0 0 1 562 0 0 12 3 84 1 0
2 0 0 2416296 306248 16904884 0 0 0 436 33101 56797 10 1 89 0 0
2 0 0 2416296 306248 16904936 0 0 0 780 29499 54581 4 1 95 0 0
4 0 0 2424264 306248 16904984 0 0 0 636 29893 54824 3 1 96 0 0
1 0 0 2424232 306248 16905036 0 0 0 372 30908 57342 5 1 94 0 0
1 0 0 2424604 306248 16905092 0 0 0 1068 28019 53190 3 1 96 0 0
df 查看磁盘信息
$ df -lh
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rootvg-lv01
58G 25G 31G 45% /
tmpfs 47G 0 47G 0% /dev/shm
/dev/sda1 190M 39M 141M 22% /boot
/dev/mapper/rootvg-lv02
482G 186G 272G 41% /data
free 查看内存信息
$ free -m
total used free shared buffers cached
Mem: 100838 98550 2288 1 298 16385
-/+ buffers/cache: 81865 18973
Swap: 0 0 0
netstat 查看网络信息
$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
TIME_WAIT 380
CLOSE_WAIT 273
SYN_SENT 1
FIN_WAIT1 3
ESTABLISHED 2978
ulimit 操作系统资源限制
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 382765
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 65535
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 65535
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
top 查看进程/线程的内存,CPU占用动态
Shift+p 按CPU占用率倒序
Shift+m 按内存占用率倒序
Shift+h 显示线程(单个进程情况)
- 总览
top - 10:42:41 up 648 days, 19:44, 2 users, load average: 1.11, 1.45, 1.99
Tasks: 371 total, 1 running, 370 sleeping, 0 stopped, 0 zombie
Cpu(s): 3.3%us, 1.6%sy, 0.0%ni, 95.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 103259124k total, 100845040k used, 2414084k free, 305828k buffers
Swap: 0k total, 0k used, 0k free, 16804588k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
113683 dev 20 0 5136m 1.2g 6316 S 6.9 1.2 58669:23 java
46066 root 20 0 12.2g 2.5g 21m S 5.3 2.5 995:43.90 java
82884 root 20 0 12.0g 834m 17m S 4.9 0.8 453:45.69 java
- 单个进程和线程
top -H -p pid
top - 10:44:11 up 648 days, 19:45, 2 users, load average: 0.75, 1.25, 1.86
Tasks: 57 total, 0 running, 57 sleeping, 0 stopped, 0 zombie
Cpu(s): 12.0%us, 3.3%sy, 0.0%ni, 83.7%id, 0.9%wa, 0.0%hi, 0.1%si, 0.0%st
Mem: 103259124k total, 100816588k used, 2442536k free, 305848k buffers
Swap: 0k total, 0k used, 0k free, 16810044k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
114032 dev 20 0 5136m 1.2g 6316 S 47.8 1.2 2397:10 [main]>worker0
113719 dev 20 0 5136m 1.2g 6316 S 2.0 1.2 459:33.61 java
113722 dev 20 0 5136m 1.2g 6316 S 2.0 1.2 459:32.09 java
113723 dev 20 0 5136m 1.2g 6316 S 2.0 1.2 459:31.99 java
引用
- JVM工具 https://docs.oracle.com/en/java/javase/13/docs/specs/man/index.html
- 常用GC参数 http://ifeve.com/useful-jvm-flags/
- GC收集 https://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf
- GC调优 https://docs.oracle.com/en/java/javase/13/gctuning/concurrent-mark-sweep-cms-collector.html

浙公网安备 33010602011771号