1 低延迟高可用Java服务的痛点
对于低延迟和高可用的Java服务,GC停顿一直是它们的痛点。
例如一个服务,被要求在100ms内要返回结果,服务可用性要求为99.99%。假设服务收到的请求速率稳定, GC的平均停顿时间为50ms,每分钟GC 5次, 服务的平均响应耗时为60ms,则0.4%(5*50ms/60000ms)的请求处理时间会因为GC停顿增加50ms,服务的可用性最低可能为99.6%,无法满足可用性要求。
ZGC(The Z Garbage Collector)是JDK 11中推出的一款低延迟垃圾回收器,可用于大内存低延迟服务的内存管理和回收。
2 GC基础概念
- 垃圾:不再使用的对象。在JVM中,指的是一个没有引用指向的对象,或者仅包含循环引用的多个对象。
- GC:Garbage Collection,垃圾回收
- STW:Stop The World,GC的停顿时间,此时所有用户线程停止活动,等待GC线程完成垃圾回收。
- 用户线程:用于执行业务逻辑的线程。
- GC线程:用于垃圾收集的线程。
- 并发:在多核条件下,用户线程和GC线程同时执行。
- 并行:在多核条件下,多个GC线程同时执行。
3 ZGC简介
3.1 特点
- 单代内存管理
- 内存分页管理:使用小、中、大三种粒度。
3.2 优点
- 停顿时间不会随着堆内存的增大而增长:ZGC几乎所有暂停都只依赖于根集合大小,停顿时间不会随着堆内存的大小而增加。
- 单次停顿时间控制在10ms之内。在实际项目中通常停顿时间小于15ms。
3.3 缺点
- 吞吐量低,不适合吞吐量优先的程序。
- CPU占用率偏高:在实际项目中,服务使用zgc后,机器CPU负载会增加10%
- 对机器CPU负载敏感:在实际项目中,发现机器的CPU负载达到到60%以上,ZGC的内存回收速度会下降,导致GC周期增长。
- 存在浮动垃圾。
- 当内存回收速度低于分配速度,可用内存不足时,会退化成阻塞回收,所有用户线程暂停,直到GC完成。
4 低延迟的原因
ZGC在标记、转移和重定位阶段几乎都是并发的,这是ZGC实现停顿时间小于10ms的最关键原因。
ZGC 只有 3 个需要 STW 的阶段,其中初始标记和初始转移只需要扫描所有根集合,STW 时间根集合 的数量成正比,不会耗费太多时间。再标记过程主要处理并发标记引用地址发生变化的对象,这些对象数量比较少,