GC优化
当Java程序性能达不到既定目标,且其他优化手段都已经穷尽时,通常需要调整垃圾回收器来进一步提高性能,称为GC优化。但GC算法复杂,影响GC性能的参数众多,且参数调整又依赖于应用各自的特点,这些因素很大程度上增加了GC优化的难度。即便如此,GC调优也不是无章可循,仍然有一些通用的思考方法
JVM基础
内存结构
主流虚拟机Hotspot VM将内存划分为不同的物理区,就是“分代”思想的体现。如图所示,JVM内存主要由新生代、老年代、永久代构成。
常见垃圾回收器
不同的垃圾回收器,适用于不同的场景。常用的垃圾回收器:
- 串行(Serial)回收器是单线程的一个回收器,简单、易实现、效率高。
- 并行(ParNew)回收器是Serial的多线程版,可以充分的利用CPU资源,减少回收的时间。
- 吞吐量优先(Parallel Scavenge)回收器,侧重于吞吐量的控制。
- 并发标记清除(CMS,Concurrent Mark Sweep)回收器是一种以获取最短回收停顿时间为目标的回收器,该回收器是基于“标记-清除”算法实现的。
参数基本策略
活跃数据的大小是指,应用程序稳定运行时长期存活对象在堆中占用的空间大小,也就是Full GC后堆中老年代占用空间的大小。
空间 | 倍数 |
---|---|
总大小 | 3-4 倍活跃数据的大小 |
新生代 | 1-1.5 活跃数据的大小 |
老年代 | 2-3 倍活跃数据的大小 |
永久代 | 1.2-1.5 倍Full GC后的永久代空间占用 |
优化步骤
GC优化一般步骤可以概括为:确定目标、优化参数、验收结果。
确定目标
明确应用程序的系统需求是性能优化的基础,系统的需求是指应用程序运行时某方面的要求,譬如: - 高可用,可用性达到几个9。 - 低延迟,请求必须多少毫秒内完成响应。 - 高吞吐,每秒完成多少次事务。
优化
通过收集GC信息,结合系统需求,确定优化方案,例如选用合适的GC回收器、重新设置内存比例、调整JVM参数等。
进行调整后,将不同的优化方案分别应用到多台机器上,然后比较这些机器上GC的性能差异,有针对性的做出选择,再通过不断的试验和观察,找到最合适的参数。
XX:MaxGCPauseMillis=500
使用G1将会受益
超过50%的Java堆被实时数据占用。
对象分配率或提升率差异很大。
该应用程序正在经历不希望的长时间垃圾收集或压缩暂停(长于0.5到1秒)。
设想验证:
- Java程序可见的不是容器资源,是宿主机的资源。在JDK191后fix,更新JDK验证后,不是这个问题
各种引用导致YGC耗时
- 套接字是Final引用,Final引用GC比较耗时,dubbo 是长连接,这样的话还好
- 不过确实在出现的问题的时候,有大量的Dubbo请求,仍然作为一个怀疑点
某个时间点请求的数据量很大,如果第一次YGC过程中无法足够快地将对象从年轻一代移动到老一代,因为旧一代没有足够的内存。则需要等safepoint,其他GC也会出现这样情况,而safepoint 如果是一个锁,那么最终所有的GC需都暂停,此过程将会是一个长耗时的过程
- 此过程尝试使用G1GC,JDK9以后默认的。官方推荐使用heap大于4G的应用(尝试中)
- 增大或减少eden 区大小(尝试中)
9111验证跟踪
未切线上流量,使用大问句压测线上使用G1GC容器
- 容器应用未挂
- CPU 8核满负荷
- GC日志分析,YGC<1.58秒,FGC<5秒
使用G1GC容器切百分之十线上流量
- 当天没有大问句,未出现问题和异常
使用G1GC容器切百分之二十线上流量
容器出问题
- 2个pod错误量突出高
- 原因 所在的CPU型号比较老,性能较差
- 运维切下线百分之十
一台datacore请求慢
- 无特别情况,日志看不出异常,仅仅表现出慢
- 原因 所在物理机load过高
使用G1GC容器切百分之十线上流量
- 对大问句做限制,但未出现大问句
- 强化容器CPU调度策略
- 容器指标各项正常
使用G1GC容器切百分之二十线上流量
- 大问句受限
- 容器指标稳健
问题阶段性总结
大问句是出现问题的导火索,其他同情况的JAVA应用没问题只是没达到9111量级
经考证jdk_131之前的版本,使用的是宿主机CPU资源,像datacache已确认
Java程序拿到是CPU核心数在没有CPU密集情况下一般情况也不会出现问题,将会增加宿主机计算资源
容器相比于虚拟机完全虚拟出一台机器,容器只是在物理机上层写资源隔离调度的代码,这是它的优势,也是它的风险.像所分配的核心数其实不是论几个的,它的单位是像4核配置里边是400000很精确的,体现出调度资源的分配
9111问题转好,主要体现在CPU使用上:G1的使用,VM参数中线程的控制,容器对CPU的调度控制