GC常用参数
- -Xmn -Xms -Xmx -Xss
年轻代 最小堆 最大堆 栈空间 - -XX:+UseTLAB
使用TLAB,默认打开 - -XX:+PrintTLAB
打印TLAB的使用情况 - -XX:TLABSize
设置TLAB大小 - -XX:+DisableExplictGC
System.gc()不管用 ,FGC - -XX:+PrintGC
- -XX:+PrintGCDetails
- -XX:+PrintHeapAtGC
- -XX:+PrintGCTimeStamps
- -XX:+PrintGCApplicationConcurrentTime (低)
打印应用程序时间 - -XX:+PrintGCApplicationStoppedTime (低)
打印暂停时长 - -XX:+PrintReferenceGC (重要性低)
记录回收了多少种不同引用类型的引用 - -verbose:class
类加载详细过程 - -XX:+PrintVMOptions
- -XX:+PrintFlagsFinal -XX:+PrintFlagsInitial
必须会用 - -Xloggc:opt/log/gc.log
- -XX:MaxTenuringThreshold
升代年龄,最大值15 - 锁自旋次数 -XX:PreBlockSpin 热点代码检测参数-XX:CompileThreshold 逃逸分析 标量替换 …
这些不建议设置
JVM调优第一步,了解JVM常用命令行参数
-
JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
-
HotSpot参数分类
标准: - 开头,所有的HotSpot都支持
非标准:-X 开头,特定版本HotSpot支持特定命令
不稳定:-XX 开头,下个版本可能取消
java -version
java -X
试验用程序:
import java.util.List;
import java.util.LinkedList;
public class HelloGC {
public static void main(String[] args) {
System.out.println("HelloGC!");
List list = new LinkedList();
for(;;) {
byte[] b = new byte[1024*1024];
list.add(b);
}
}
}
查看默认参数
查看GC详细信息
一条GC信息的详细信息如下:
关于上图中的Times含义:在linux中的times代表:
Heap Dump的含义
eden space 5632K, 94% used [0x00000000ff980000,0x00000000ffeb3e28,0x00000000fff00000)
后面的内存地址指的是,起始地址,使用空间结束地址,整体空间结束地址
调优实战
调优前的基础概念:
- 吞吐量:用户代码时间 /(用户代码执行时间 + 垃圾回收时间)
- 响应时间:STW越短,响应时间越好
所谓调优,首先确定,追求啥?吞吐量优先,还是响应时间优先?还是在满足一定的响应时间的情况下,要求达到多大的吞吐量…
问题:
科学计算,吞吐量。数据挖掘,thrput。吞吐量优先的一般:(PS + PO)
响应时间:网站 GUI API (1.8 G1)
什么是调优?
- 根据需求进行JVM规划和预调优
- 优化运行JVM运行环境(慢,卡顿)
- 解决JVM运行过程中出现的各种问题(不完全等同于解决OOM的问题,因为前面两项也很重要)
并发:
- QPS
- TPS
淘宝双11并发历年最高54万,据说12306并发比淘宝更高,号称上百万
调优,从规划开始
-
调优,从业务场景开始,没有业务场景的调优都是耍流氓
-
无监控(压力测试,能看到结果),不调优(可以调整业务逻辑)
-
步骤:
- 熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
- 响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)
- 吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
- 选择回收器组合
- 计算内存需求(没有一定之规,是经验值。 1.5G -> 16G,突然卡顿了,为啥?)
- 选定CPU(预算能买到的,当然是越高越好,CPU多核,可以多线程运行呀)
- 设定年代大小、升级年龄
- 设定日志参数,这是Java虚拟机的参数,也可以在Tomcat里面配置,貌似是在叫catalinaoptions里面指定java日志的参数。
-Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation-XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
5个日志文件,循环产生。生产环境中的日志参数一般这么设置。
%t
是生成时间的意思。
- 或者每天产生一个日志文件
- 观察日志情况
- 熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
如何根据需求进行JVM规划和预调优?
有人要问你,你应该选用多大的内存?什么样的垃圾回收器组合?你怎么回答?
-
案例1:垂直电商,最高每日百万订单,处理订单系统需要什么样的服务器配置?
这个问题比较业余,因为很多不同的服务器配置都能支撑(1.5G 16G 都有可能啊)
我们做一个假设吧,1小时360000个订单。集中时间段, 100个订单/秒,(找一小时内的高峰期,可能是1000订单/秒)。我们就要找到这个最高峰的时间,保证你的架构能够承接的住。
大多数情况下,是靠经验值,然后做压测。
如果非要计算的话,你预估一下,一个订单对象产生需要多少内存?512K * 1000 = 500M内
专业一点的问法:要求响应时间在多少时间的情况下,比如100ms,我们去挑一个市面上性价比比较高的服务器,做压测去测试,再不行加内存,再不行,就上云服务器…
这样说就OK了 -
案例2:12306遭遇春节大规模抢票应该如何支撑?(这个是架构上的一个设计,和调优关系不大)
12306应该是中国并发量最大的秒杀网站:号称并发量最高100W
架构模型:CDN -> LVS -> NGINX -> 业务系统 -> 100台机器,每台机器1W并发(单机10K问题),目前这个问题已解决,主要是用redis
.业务流程:普通电商订单 -> 下单 ->订单系统(IO)减库存 ->生成订单,等待用户付款
12306的一种可能的模型,是异步来进行的: 下单 -> 减库存 和 订单(redis kafka) 同时异步进行 ->等付款,付完款,持久化到Hbase, MySQL等等
.
减库存最后还会把压力压到一台服务器,怎么办?可以做分布式本地库存 + 单独服务器做库存均衡
大流量的处理方法:分而治之,每台机器只减自己机器上有的库存
流量倾斜的问题怎么解决?比如有的机器上已经没库存了,有的机器上还剩很多?
这时候你还需要一台单独的服务器,去做所有服务器的平衡,如果某台服务器没库存了,从别的机器上挪一些过去。 -
怎么得到一个事务会消耗多少内存?
1、弄台机器,看能承受多少TPS?是不是达到目标?扩容或调优,让它达到
2、用压测来确定
优化环境
- (这个可以稍微改一下写进简历中)
有一个50万PV的文档资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G
的堆,用户反馈网站比较缓慢。因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了!- 为什么原网站慢?
因为很多用户浏览数据,很多用户浏览导致很多数据Load到内存,产生了很多文档对应的Java包装对象(而不是文档对象,文档本身可以走Nginx)。内存不足,频繁GC,STW长,响应时间变慢 - 为什么会更卡顿?
内存越大,FGC时间越长 - 咋办?
PS 换成 PN + CMS,或者 G1
或者业务上的调整,文档不走JVM
- 为什么原网站慢?
- 系统CPU经常100%,如何调优?(面试高频)
这样回答:推理过程是:CPU100%,那么一定有线程在占用系统资源,所以- 找出哪个进程cpu高(top命令)
- 该进程中的哪个线程cpu高(top -Hp)
- 如果是java程序,导出该线程的堆栈 (jstack)
- 查找哪个方法(栈帧)消耗时间,哪个方法调用的哪个方法 (jstack),然后去看这个方法的代码
- 工作线程占比高 | 垃圾回收线程占比高
- 系统内存飙高,如何查找问题?(面试高频)
- 导出堆内存 (jmap)
- 分析 (jhat jvisualvm mat jprofiler … )
- 如何监控JVM
- jstat jvisualvm jprofiler arthas top…