说在最前
性能调优包含多个层次,架构调优、代码调优、数据库调优、操作系统调优、JVM调优等。其中,架构调优和代码调优对系统的影响最大。JVM调优听起来高大上,实际上,一般不会进行到JVM调优,在JVM调优之前会进行架构调优、代码调优,而JVM调优是系统性能提升的最后一道保障,也就是说JVM调优之后,就没有性能提升的手段了,所有一般系统都是从上层来调优。但是此篇还是讲解JVM调优,不要跑偏。(能想到的作用:和面试官battle)
JVM调优原则
- 大多数的Java应用不需要进行JVM优化;
- 大多数导致GC问题的原因是代码层面的问题导致的(代码层面);
- 上线之前,应先考虑将机器的JVM参数设置到最优;
- 减少创建对象的数量(代码层面);
- 减少使用全局变量和大对象(代码层面);
- 优先架构调优和代码调优,JVM优化是不得已的手段(代码、架构层面);
- 分析GC情况优化代码比优化JVM参数更好(代码层面);
JVM调优步骤
- 分析GC日志及dump文件,判断是否需要优化,确定瓶颈问题点;
- 确定JVM调优量化目标;
- 确定JVM调优参数(根据历史JVM参数来调整);
- 依次调优内存、延迟、吞吐量等指标;
- 对比观察调优前后的差异;
- 不断的分析和调整,直到找到合适的JVM参数配置;
- 找到最合适的参数,将这些参数应用到所有服务器,并进行后续跟踪。
JVM调优目标
- 延迟:GC低停顿和GC低频率;
- 低内存占用;
- 高吞吐量;
参数
# JVM启动参数不换行
# 设置堆内存
-Xmx4g -Xms4g
# 指定GC算法
-XX:+UseG1GC -XX:MaxGCPauseMillis=50
# 指定GC并行线程数
-XX:ParallelGCThreads=4
# 设置年轻的和老年代的内存比例为 1:4
-XX:NewRatio=4
# 设置新生代 Eden 和 Survivor 比例为 8:2
-XX:SurvivorRatio=8
# 开启打印 gc 信息
-XX:+PrintGC
# 打印GC日志
-XX:+PrintGCDetails -XX:+PrintGCDateStamps
# 指定GC日志文件
-Xloggc:gc.log
# 指定Meta区的最大值
-XX:MaxMetaspaceSize=2g
# 设置单个线程栈的大小
-Xss1m
# 指定堆内存溢出时自动进行Dump
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/
# 指定默认的连接超时时间
-Dsun.net.client.defaultConnectTimeout=2000
-Dsun.net.client.defaultReadTimeout=2000
# 指定时区
-Duser.timezone=GMT+08
# 设置默认的文件编码为UTF-8
-Dfile.encoding=UTF-8
一般来说,JDK8及以下开启日志:
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:gc.log
JVM调优工具
JDK自带了很多监控工具,都位于JDK的bin目录下,最常用的是jconsole和jvisualvm。
JVM调优连环炮:怎么打出线程栈信息
思路:可以说一下jps、top、jstack这几个命令
- 输入jps,获得进程号。
- top -Hp pid 获取本进程中所有线程的CPU耗时性能
- jstack pid命令查看当前java进程的堆栈状态
- 或者 jstack -l > /tmp/output.txt 把堆栈信息打到一个txt文件。
- 可以使用fastthread 堆栈定位,fastthread.io