美文网首页
(12)ZGC美团

(12)ZGC美团

作者: hedgehog1112 | 来源:发表于2020-11-21 12:35 被阅读0次

    JDK 11中低延迟垃圾回收器,设计目标:

        停顿时间 < 10ms,不随堆、活跃对象的大小而增加

        支持8MB~4TB的堆(未来支持16TB)

    概要:GC之痛(CMS和G1停顿时间瓶颈) 、ZGC原理(更短)、ZGC调优实践、升级ZGC效果

    一、GC之痛

    可用性99.99%未达到:CMS单次Young GC 40ms,一分钟10次,接口响应时间30ms。( 40ms + 30ms ) * 10次 / 60000ms = 1.12%

    四个STW:两次标记、复制(耗时长)、清理。  ps:G1和CMS的Young GC,标记-复制全过程STW

    二、ZGC原理

    标记、转移和重定位阶段几乎都并发

    1、三个STW:1\2)初始标记转移(短):,只扫描所有GC Roots,处理时间和GC Roots数量成正比 3)再标记(短):最多1ms,超过1ms再次进入并发标记

        STW只依赖GC Roots大小,和堆或者活跃对象没关系

    2、ZGC关键技术

    着色指针读屏障,实现并发转移,转移过程准确访问对象。

    原理:1)old:转移时,应用线程不停访问对象。可能旧地址造成错误。2)ZGC访问触发“读屏障”,发现对象移动(着色指针判断)“读屏障”更到对象新地址

    (1)着色指针

    将信息存在指针中,ZGC仅支持64位系统,把64位虚拟地址空间划分为多个子空间。ZGC仅用0~41位,42~45存元数据(存活信息,和传统gc完全不同,第47~63位固定为0

    创建对象时:1)空间申请虚拟地址(不映射到真正物理地址),2)ZGC同时为该对象在M0、M1和Remapped分别申请虚拟地址(三个虚拟对应同一物理地址,同一时间只一个有效),3)设置三个,因“空间换时间”,降低GC停顿时间

    [0~4TB) 对应Java堆,[4TB ~ 8TB) 称为M0地址空间,[8TB ~ 12TB) 称为M1地址空间,[12TB ~ 16TB) 预留未使用,[16TB ~ 20TB) 称为Remapped空间。

    (2)读屏障

    JVM应用代码插入一小段代码,应用线程读对象引用执行。注意:仅“从堆中读取对象引用”才触发

    作用:对象标记和转移时,确定对象引用地址是否满足条件,作出相应动作。

    读屏障示例

    (3)ZGC并发处理演示(gc中地址视图切换过程)

        1) 初始化地址视图设置为Remapped。程序运行,内存中分配对象,满足条件后gc,标记

        2) 并发标记阶段:第一次标记为M0,如对象GC标记或者应用线程访问过,将对象Remapped调为M0(说明对象活跃)

      3) 并发转移阶段:再次被设为Remapped。如GC转移或应用线程访问过,将对象从M0调整为Remapped。ps:区别第二次标记,调为M1

    “着色指针和读屏障”用在并发转移、标记阶段,1)传统回收器:已标记进行一次内存访问,并将对象存活信息放在对象头;2)ZGC:只设置指针地址第42~45位即可,因为是寄存器访问,比访问内存更快

    三、ZGC调优实践

    1、重要参数

    -Xms -Xmx:堆最大/小内存,都设为10G,堆内存保持不变

    -XX:ReservedCodeCacheSize -XX:InitialCodeCacheSize: CodeCache的大小, JIT编译的代码都放在CodeCache中,一般服务64m或128m足够。

    -XX:+UnlockExperimentalVMOptions -XX:+UseZGC:启用ZGC

    -XX:ConcGCThreads:并发回收垃圾的线程。默认总核数12.5%,8核CPU是1。调大GC变快,但占用CPU资源,影响吞吐

    -XX:ParallelGCThreads:STW阶段使用线程数,默认总核数60%。

    -XX:ZCollectionInterval:ZGC最小时间间隔,秒。

    -XX:ZAllocationSpikeTolerance:ZGC触发自适应算法的修正系数,默认2,数值越大,越早的触发ZGC。

    -XX:+UnlockDiagnosticVMOptions -XX:-ZProactive:是否启用主动回收,默认开启,这里表示关闭。

    -Xlog:设置GC日志中的内容、格式、位置以及每个日志的大小。

    2、理解ZGC触发时机

    调优第一目标:保证GC完成之前,新对象不会占满堆,导致线程停顿,秒级。触发机制:

        1)阻塞内存分配请求触发:来不及回收,将堆占满时,阻塞。日志关键字“Allocation Stall”。

        2)基于分配速率的自适应算法(最主要):根据近期对象分配速率GC时间,计算内存占用阈值,触发GC”。ZAllocationSpikeTolerance控制阈值大小,默认2,越大越早触发。“Allocation Rate”。

        3)基于固定时间间隔:ZCollectionInterval控制,适合增流量场景,自适应算法触发可能会过晚,阻塞。“Timer”。

        4)主动触发规则:类似3,间隔不固定,ZGC自行算,通过-ZProactive关闭,以免GC频繁,影响服务可用性。“Proactive”。

        5)预热规则:服务刚启动,不需关注“Warmup”。

        6)外部触发:代码中显式调System.gc()。System.gc()”。

        7)元数据分配触发:元数据区不足,不需关注。Metadata GC Threshold

    3、理解ZGC日志(完整GC过程)

    该日志过滤了进入安全点的信息。正常情况,在一次GC过程中还穿插着进入安全点的操作。

    Start:开始GC,GC触发原因。上图是自适应算法。

    Phase-Pause Mark Start:初始标记,会STW。

    Phase-Pause Mark End:再次标记,会STW。

    Phase-Pause Relocate Start:初始转移,会STW。

    Heap信息:记录GC中Mark、Relocate前后堆大小变化。High和Low记录最大/小值,如100%,GC一定内存分配不足,更早更快触发GC时机

    GC信息统计:定时打印垃圾收集信息,10秒内、10分钟内、10个小时内,启动到现在所有统计信息。排查异常点

    4、理解ZGC停顿原因(6种)

        1)初始标记:日志中Pause Mark Start。

        2)再标记:日志中Pause Mark End。

        3)初始转移:日志中Pause Relocate Start。

        4)内存分配阻塞:内存不足阻塞"Allocation Stall"。

        4)安全点所有线程进入安全点才能GC,定期进入判断是否要GC。先等后,直到所有挂起

        6)dump线程、内存:比如jstack、jmap命令

    5、案例一:秒杀流量突增,出现性能毛刺

    日志:大量“Allocation Stall”,多出现在“自适应算法,内存分配阻塞

    解决方法:1)固定间隔触发-XX:ZCollectionInterval。调为5秒,更短

                      2)更早触发GC,增大-XX:ZAllocationSpikeTolerance,预测内存分配速率,默认值2设置5,值越大越早触发

    6、案例二:压测时,流量逐渐增大一定程度后,出现性能毛刺

    日志信息:平均1秒GC/次,两次几乎没间隔,内存分配阻塞

    分析:触发及时,但内存标记和回收慢

    解决方法:加快并发标记和回收速度,增大-XX:ConcGCThreads默认值核数1/8,8核是1。影响系统吞吐,如GC间隔时间 > GC周期,不建议调整

    GC Roots 数量大,单次GC停顿时间长

    四、升级ZGC效果

    1、延迟降低

    低延迟(TP999 < 200ms)场景中收益较大:

        TP999(99.9%请求都能被响应的最小耗时):下降12~142ms,下降幅度18%~74%。

        TP99:下降5~28ms,下降幅度10%~47%。

    超低延迟(TP999 < 20ms)和高延迟(TP999 > 200ms)收益不大,瓶颈不是GC,是外部依赖的性能。

    2、吞吐下降

    不适合吞吐量优先场景。CMS升级ZGC,吞吐量明显降低。1)ZGC单代,每次处理对象更多,耗CPU2)读屏障,耗费额外计算资源

    总结:性能优秀:全部并发;STW极短<10ms;得益于着色指针和读屏障

    https://zhuanlan.zhihu.com/p/170572432

    相关文章

      网友评论

          本文标题:(12)ZGC美团

          本文链接:https://www.haomeiwen.com/subject/ngjdiktx.html