什么是JVM调优?
其实无非就是调节JVM启动时配置的那些参数。例如:
- -Xmx:最大堆内存,如:-Xmx512m
- -Xms:初始时堆内存,如:-Xms256m
- -XX:MaxNewSize:最大年轻区内存
根据我们当前的机器配置,选择适当的GC收集器,调节堆内存的大小,乃至与一些更加细致入微的一些参数,如是否开启偏向锁等等。。。
JVM启动参数的概述:
标准参数:
以 "-" 开头的java启动参数,这类参数在jdk里所有的版本都支持。如下
- -version:输出产品版本并退出
- -help:输出帮助消息
可以通过 命令行输入 java 进行查看。
非标参数:
以 "-X" 开头的java启动参数,这类参数是可能会被剔除掉的。如下图
- -Xms<size>:设置初始 Java 堆大小
- -Xmx<size>:设置最大 Java 堆大小
可以通过 命令行输入 java -X 进行查看。
不稳定参数:
以 "-XX" 开头的参数,这类参数是不确定的参数,可能在不同的环境,不同的版本,都有不一样的值和参数。但是这个列表内的参数也是我们JVM调优的重点内容,我们JVM调优主要就是调节这里面的一些参数。如下:
这是JAVA官方提供JDK1.8的启动参数文档:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html#BABFAFAE
语法结构:
- Boolean options are turned on with
-XX:+<option>
and turned off with-XX:-<option>
.Disa - Boolean 类型的参数通过 -XX:+<option> 和 --XX:-<option>控制打开或者关闭
- Numeric options are set with
-XX:<option>=<number>
. Numbers can include 'm' or 'M' for megabytes, 'k' or 'K' for kilobytes, and 'g' or 'G' for gigabytes (for example, 32k is the same as 32768). - 数字类型的惨数通过 -XX:<option>=<number>进行设定,数字类型包括兆字节:'m'或者'M',千字节:'k'或者'K',千兆字节:'g'或者'G'(例如,32K 相当于 32768)。
- String options are set with
-XX:<option>=<string>
, are usually used to specify a file, a path, or a list of commands - 字符串类型的参数设置为
-XX:<option>=<string>
,通常用于指定文件,路径或命令列表
常见的参数设定:
垃圾回收器组合:
- -XX:+UseSerialGC = Serial + Serial Old
- -XX:+UseParNewGC = ParNew + Serial Old
- -XX:+UseConc(urrent)MarkSweepGC = ParNew + CMS + Serial Old
- -XX:+UseParallelGC = Parallel Scavenge + Parallel Old
- -XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old
- -XX:+UseG1GC = G1
GC常用的参数:
- -Xmn = 年轻代
- -Xms = 最小堆
- -Xmx = 最大堆,(最好将最小堆内存和最大堆内存设置为一样的,避免了JVM进行扩充,扩充有时很消耗性能)
- -Xss = 栈空间
- -XX:+UseTLAB = 使用TLAB 默认打开
- -XX:PrintTLAB = 打印TLAB的使用情况
- -XX:+DisableExplictGC = System.gc()不管用
- -XX:+PrintGC
- -XX:+PrintGCDetails
- -XX:+PrintGCTimeStamps
- -Xloggc:filename
Parallel 常用的参数:
- -XX:SurvivorRatio = 新生代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:为3,表示Eden:Survivor=3:2,一个Survivor区占整个新生代的1/5
- -XX:PreTenureSizeThreshold = 大对象到底多大
- -XX:MaxTenuringThreshold = 多大年龄进入老年代
- -XX:+ParallelGCThreads = 并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同
- -XX:+UseAdaptiveSizePolicy = 自动选择各区大小比例
- -XX:GCTimeRatio = 设置GC时间占用程序运行时间的百分比
- -XX:MaxGcPauseMillis = 停顿时间
CMS常用参数:
- -XX:+UseConcMarkSweepGC
- -XX:ParallelCMSThreads = CMS线程数量
- -XX:CMSInitiatingOccupancyFraction = 使用多少比例的老年代后开始CMS收集,默认是68%,如果频繁发生SerialOld卡顿应该适当缩小该值
- -XX:UseCMSCompactAtFullCollection = 在FGC时进行压缩
- -XX:CMSFULLGCsBeforeCompaction = 多少次FGC之后进行压缩
- -XX:+CMSClassUnloadingEnabled = 是否扫描PermGen(方法区),卸载不适用的类
- -XX:CMSInitiatingPermOccupancyFraction = 达到什么比例时进行Perm回收
G1常用参数:
- -XX:+UseG1GC
- -XX:MaxGCPauseMillis = 建议值,G1会尝试调整Uoung区的快数来达到这个值
- -XX:GCPauseIntervalMillis = GC的间隔时间
- -XX:+G1HeapRegionSize = 分区大小,1 2 4 8 16 32 。
- -XX:G1NewSizePercent = 新生代最小比例,默认5%
- -XX:G1MaxNewSizePerrent = 新生代最大比例,默认60%
- -XX:GCTimeRation = GC时间建议比例,G1会根据这个值调整堆空间
- -XX:ConcGCThreads = 线程数量
- -XX:InitiatingHeapOccupancyPercent = 启动G1的堆空间占用比例
以上来源于,马士兵老师的"马士兵课程",和周志明老师的"深入理解JAVA虚拟机"等。。。
依据什么进行调优呢?(常用的工具)
一些常用排查问题的JVM工具:
- top = 查看内存和cpu 使用情况
- jps = 查看java进程的进程号
- jinfo = JAVA进程的一些基本信息,和JVM启动时的一些参数
- jstat = 堆内存的使用情况,各个区域的内存占用
- jstack = 该进程内的所有的线程,(判断是否死锁等)
- jmap = 查看当前jvm内的对象数量 (不建议在线上使用,他会引起STW)
-
jvisualvm = 堆转储文件的可视化分析工具。
阿里的arthas:
- jvm = 查看java进程的JVM信息
- dashboard = 观察系统情况
- thread = 定位线程问题
- sc = 查询class
- sm = 查询方法
- trace = 跟踪方法的调用链(可以显示调用时间)
- heapdump = 导出内存堆(不建议在线上使用,他会引起STW)
阿里巴巴arthas的官方命令介绍:https://arthas.gitee.io/commands.html
常见的问题?
CPU飙高:
- 首先通过top 命令查看对应的进程,是哪个进程占用cpu。如果是java进程则进入下一步。
- 通过jstack 或者 arthas的thread找到这个进程内占用cpu过高的线程。如果是GC线程则进入下一个问题(OOM)进行排查,如果是普通的用户线程则进入下一步。
- 根据arthas的sc,和sm命令查找出对应线程所使用的类和方法。下一步。
- 通过arthas的trace命令对该方法的调用链进行跟踪,结合代码,从而具体的问题出响应慢,执行时间久的代码位置。看看是否出现复杂的数学计算等具体原因。
OOM
- 首先确定该环境是否允许STW,如果不允许则,通过-XX:PrintGC等参数,将GC日志输出出来,进行排查。如果允许,则进入下一步
- 可以通过,jmap或者arthas的heapdump命令将堆转储文件下载下来。下一步
- 通过jvisualvm等堆转储文件分析工具,对堆内存进行分析,从而找出是什么类过多的占用内存空间,结合代码进行分析