JVM调优
主要调这几个指标,GC停顿时间,吞吐量,FullGC次数。
当我们发现线上出现频繁的gc的时候,不能直接用jmap dump内存快照,
因为jmap dump快照(dump下来得到快照会很大)的时候回造成卡顿。
我们可以让运维临时隔离这台服务器,然后再dump内存快照.
我们调优的原则是在用户可接收的停顿时间范围内,让更多的gc控制在young区域,不让更多的对象进入到老年代.
- jstat -gc pid 1000 10 , 隔1秒执行一次gc观察,共10秒.
Fullgc造成的原因:
- 动态年龄判断机制进入老年代
- 触发了空间担保(s区问old区要空间,survivor)
- 大对象进入到老年代(我们可以设置老年代进入的比例)
- System.gc() 显式调用
- 关于日志分析
我们可以通过printgc log 获取到gc log日志,然后通过gc viewer查看吞吐量
可以通过这个查看吞吐量,停顿时间,fullgc次数.
- 提供实际案例。
并发促销情况,每秒3k qps,一个订单1kb大小.
1000*30 = 30M左右,堆内存young:old = 1:2 ,算出young区大小,
大约45/s左右,会触发gc, 不仅会发生younggc,也可能有old gc.临时调整young old 区比例。
增加机器?
调整堆内存比例?
内存溢出 | A | B |
---|---|---|
reason: 内粗泄漏导致的溢出,大并发下导致的溢出 | C | C |
mat, 验证码 cdn,模板,缓存,限流,tomcat调优或者替换成underrow,内存队列,mq削峰,jvm缓存,ngnx缓存,分布式锁,zk通知Nginx端活动结束,redis资源分段,tomcat参数调优,es参数调优,线程池合理传参数设置,集群部署 |
- 措施
- 首先要排除是否是代码问题,比如for循环中有lamder表达式.
top命令查看等 - 加机器
- 临时调整堆分区比例(g1会adative分区比例,所以不需要设置比例大小),
只需要设置堆空间大小. - 选择合适的垃圾收集器
比如当下用的很多的G1.
CMS+Parrel GC.
50%以上的对象存活
对象分配和晋升的速度很快
8g(起码)以上的的内存
停顿时间在500ms以内的
- 临时调整gc发生的堆空间占比,默认是45%
- 不断的调整pausetime,在吞吐量,停顿时间,gc频率中取得相对满意的值,
200 - 500 ms 时间大小之间做调整.
以上全是理论的
来看几个实际案例;
- c++程序员重写了finalize方法
- for 中lamder表达式(生成了.class对象),metaspace溢出风险
- 内存泄漏导致的溢出,三方的工具类验证码工具类
- 显示调用system.gc
- redis 分布式锁未释放,占用的内存不断飙升
todo 的案例