GC 调优实战
JVM调优第一步,了解JVM常用命令行参数
- JVM的命令行参数参考:docs.oracle.com/javase/8/do…
- HotSpot参数分类
标准: – 开头,所有的HotSpot都支持
非标准:-X 开头,特定版本HotSpot支持特定命令
不稳定:-XX 开头,下个版本可能取消
java -version
java -X
比如搜索CMS相关的命令可以使用: java -XX:+PrintFlagsFinal -version | grep CMS
1、 区分概念:内存泄漏memory leak,内存溢出out of memory
2、 java -XX:+PrintCommandLineFlags 可以将隐式或显式传给虚拟机的参数输出 -XX:+PrintGC 打印GC信息 PrintGCDetails 打印GC详细 PrintGCTimeStamps 打印带时间戳的 PrintGCCauses打印GC原因
3、 java -Xmn10M 新生代大小 -Xms40M最小堆大小 -Xmx60M最大堆大小 (最小堆和最大堆一般生产环境中设置成一样的大小,因为设置不同的大小,在内存弹性收缩时会浪费CPU资源)
4、 java -XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags HelloGC
5、 java -XX:+PrintFlagsInitial 默认参数值
6、 java -XX:+PrintFlagsFinal 最终参数值
7、 java -XX:+PrintFlagsFinal | grep xxx 找到对应的参数
8、 java -XX:+PrintFlagsFinal -version |grep GC
PS GC日志详解
每种垃圾回收器的日志格式是不同的!
PS日志格式
[GC (Allocation Failure) [ParNew: 34897K->458K(39296K), 0.0114525 secs] 34897K->458K(126720K), 0.0114821 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
GC :GC类型youngGC,Full GC表示Full GC Allocation Failure: GC原因 ParNew:34897K->458k(39296K),0.0114525 secs:新生代空间由多少->多少(年轻代总空间),花费时间 34897K->458K(126720K), 0.0114821 secs:回收前堆大小->回收后堆大小(总堆大小),花费时间 Times: user=0.00 sys=0.00, real=0.01 secs:Linux time ls
如果产生堆内存溢出则会打印出堆内存的情况,heap dump部分:
Heap
par new generation total 39424K, used 8557K [0x0000000740000000, 0x0000000742ac0000, 0x0000000754cc0000)
eden space 35072K, 24% used [0x0000000740000000, 0x000000074085b578, 0x0000000742240000)
from space 4352K, 0% used [0x0000000742240000, 0x0000000742240000, 0x0000000742680000)
to space 4352K, 0% used [0x0000000742680000, 0x0000000742680000, 0x0000000742ac0000)
concurrent mark-sweep generation total 87424K, used 742K [0x0000000754cc0000, 0x000000075a220000, 0x00000007c0000000)
Metaspace used 3592K, capacity 4536K, committed 4864K, reserved 1056768K
class space used 398K, capacity 428K, committed 512K, reserved 1048576K
eden space 5632K, 94% used [0x00000000ff980000,0x00000000ffeb3e28,0x00000000fff00000)
后面的内存地址指的是,起始地址,使用空间结束地址,整体空间结束地址
total = eden + 1个survivor
调优前的基础概念:
并发数 并发数是指系统同时能处理的请求数量,这个也是反应了系统的负载能力。
响应时间 响应时间是一个系统最重要的指标之一,它的数值大小直接反应了系统的快慢。响应时间是指执行一个请求从开始到最后收到响应数据所花费的总体时间。
吞吐量 吞吐量是指单位时间内系统能处理的请求数量,体现系统处理请求的能力,这是目前最常用的性能测试指标。
所谓调优,首先确定,追求啥?吞吐量优先,还是响应时间优先?还是在满足一定的响应时间的情况下,要求达到多大的吞吐量…
问题:
科学计算,吞吐量。数据挖掘。吞吐量优先的一般:(PS + PO)
响应时间:网站 GUI API (1.8 G1)
什么是调优?
1、 根据需求进行JVM规划和预调优
2、 优化运行JVM运行环境(慢,卡顿)
3、 解决JVM运行过程中出现的各种问题(OOM)
调优,从规划开始
- 调优,从业务场景开始,没有业务场景的调优都是耍流氓
- 无监控(压力测试,能看到结果),不调优
- 步骤:
- 熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
- 响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)
- 吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
- 选择回收器组合
- 计算内存需求(经验值 1.5G 16G)
- 选定CPU(越高越好)
- 设定年代大小、升级年龄
- 设定日志参数
- -Xlogg/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
- 或者每天产生一个日志文件
- 观察日志情况
- 熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
- 案例1:垂直电商,最高每日百万订单,处理订单系统需要什么样的服务器配置?
这个问题比较业余,因为很多不同的服务器配置都能支撑(1.5G 16G)
1小时360000集中时间段, 100个订单/秒,(找一小时内的高峰期,1000订单/秒)
经验值,
非要计算:一个订单产生需要多少内存?512K * 1000 500M内存
专业一点儿问法:要求响应时间100ms
压测!
- 案例2:12306遭遇春节大规模抢票应该如何支撑?
12306应该是中国并发量最大的秒杀网站:
号称并发量100W最高
CDN -> LVS -> NGINX -> 业务系统 -> 每台机器1W并发(10K问题) 100台机器
普通电商订单 -> 下单 ->订单系统(IO)减库存 ->等待用户付款
12306的一种可能的模型: 下单 -> 减库存 和 订单(redis kafka) 同时异步进行 ->等付款
减库存最后还会把压力压到一台服务器
可以做分布式本地库存 + 单独服务器做库存均衡
大流量的处理方法:分而治之
- 怎么得到一个事务会消耗多少内存?
- 弄台机器,看能承受多少TPS?是不是达到目标?扩容或调优,让它达到
- 用压测来确定
优化环境
1、 有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G 的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G 的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了
1. 为什么原网站慢? 很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW长,响应时间变慢
2. 为什么会更卡顿? 内存越大,FGC时间越长
3. 咋办? PS -> PN + CMS 或者 G1
2、 系统CPU经常100%,如何调优?(面试高频) CPU100%那么一定有线程在占用系统资源,
1. 找出哪个进程cpu高(top)
2. 该进程中的哪个线程cpu高(top -Hp)
3. 导出该线程的堆栈 (jstack)
4. 查找哪个方法(栈帧)消耗时间 (jstack)
5. 工作线程占比高 | 垃圾回收线程占比高
3、 系统内存飙高,如何查找问题?(面试高频)
1. 导出堆内存 (jmap)
2. 分析 (jhat jvisualvm mat jprofiler ... )
4、 如何监控JVM
1. jstat jvisualvm jprofiler arthas top...