1. 简介

GC回收周期大体如下图所示:

GC回收周期包括如下11个子阶段:

  • phase 1:初始标记,需要STW
  • phase 2:并发标记
  • phase 3:标记结束,需要STW
  • phase 4:并发处理软引用、弱引用
  • phase 5:并发重置Relocation Set
  • phase 6:并发销毁可回收页
  • phase 7:内存验证
  • phase 8:并发选择Relocation Set
  • phase 9:并发准备Relocation Set
  • phase 10:开始Relocate,STW
  • phase 11:并发Relocate

出于回收效率的考虑,remap过程放在下一个回收周期的并发标记子阶段进行。

2. 代码分析

2.1 入口

ZGC的入口在ZCollectedHeap collect方法

  • 调用ZDriver的collect方法

zCollectedHeap.cpp

void ZCollectedHeap::collect(GCCause::Cause cause) {_driver->collect(cause);
}

根据传入的GCCause,判断使用同步消息还是异步消息。

  • ZGC自身的触发策略都使用异步消息,包括rule_timer、rule_warmup、rule_allocation_rate、rule_proactive
  • metaspace GC使用异步消息
  • 其他情况使用同步消息

zDriver.cpp

void ZDriver::collect(GCCause::Cause cause) {switch (cause) {case GCCause::_wb_young_gc:case GCCause::_wb_conc_mark:case GCCause::_wb_full_gc:case GCCause::_dcmd_gc_run:case GCCause::_java_lang_system_gc:case GCCause::_full_gc_alot:case GCCause::_scavenge_alot:case GCCause::_jvmti_force_gc:case GCCause::_metadata_GC_clear_soft_refs:// Start synchronous GC_gc_cycle_port.send_sync(cause);break;case GCCause::_z_timer:case GCCause::_z_warmup:case GCCause::_z_allocation_rate:case GCCause::_z_allocation_stall:case GCCause::_z_proactive:case GCCause::_metadata_GC_threshold:// Start asynchronous GC_gc_cycle_port.send_async(cause);break;case GCCause::_gc_locker:// Restart VM operation previously blocked by the GC locker_gc_locker_port.signal();break;default:// Other causes not supportedfatal("Unsupported GC cause (%s)", GCCause::to_string(cause));break;}
}

2.2 消息机制

ZGC使用ZMessagePort类传递消息,ZMessagePort内部使用了ZList队列。

zMessagePort.hpp

class ZMessagePort {
private:typedef ZMessageRequest<T> Request;Monitor        _monitor;bool           _has_message;T              _message;uint64_t       _seqnum;ZList<Request> _queue;public:ZMessagePort();void send_sync(T message);void send_async(T message);T receive();void ack();
};

同步消息逻辑如下:

  • 首先构造request
  • request入队
  • 通知消费者
  • 如果是同步消息,需要等待request处理完

zMessagePort.inline.hpp

template <typename T>
inline void ZMessagePort<T>::send_sync(T message) {Request request;{// Enqueue messageMonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag);request.initialize(message, _seqnum);_queue.insert_last(&request);ml.notify();}// Wait for completionrequest.wait();{// Guard deletion of underlying semaphore. This is a workaround for a// bug in sem_post() in glibc < 2.21, where it's not safe to destroy// the semaphore immediately after returning from sem_wait(). The// reason is that sem_post() can touch the semaphore after a waiting// thread have returned from sem_wait(). To avoid this race we are// forcing the waiting thread to acquire/release the lock held by the// posting thread. https://sourceware.org/bugzilla/show_bug.cgi?id=12674MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag);}
}

消息消费者负责消费队列中的消息,如果是异步消息,则直接读取类变量_message。

zMessagePort.inline.hpp

template <typename T>
inline T ZMessagePort<T>::receive() {MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag);// Wait for messagewhile (!_has_message && _queue.is_empty()) {ml.wait(Monitor::_no_safepoint_check_flag);}// Increment request sequence number_seqnum++;if (!_has_message) {// Message available in the queue_message = _queue.first()->message();_has_message = true;}return _message;
}

2.3 开始gc cycle

ZDriver启动一个线程,死循环判断是否应该启动gc cycle

  • start_gc_cycle调用ZMessagePort的receive方法等待启动请求
  • 调用run_gc_cycle方法,执行GC
  • 执行GC后,调用end_gc_cycle,ACK启动请求

zDriver.cpp

void ZDriver::run_service() {// Main loopwhile (!should_terminate()) {const GCCause::Cause cause = start_gc_cycle();if (cause != GCCause::_no_gc) {run_gc_cycle(cause);end_gc_cycle();}}
}GCCause::Cause ZDriver::start_gc_cycle() {// Wait for GC requestreturn _gc_cycle_port.receive();
}void ZDriver::end_gc_cycle() {// Notify GC cycle completed_gc_cycle_port.ack();// Check for out of memory conditionZHeap::heap()->check_out_of_memory();
}

run_gc_cycle中,顺序执行GC的11个子阶段。

zDriver.cpp

void ZDriver::run_gc_cycle(GCCause::Cause cause) {ZDriverCycleScope scope(cause);// Phase 1: Pause Mark Start{ZMarkStartClosure cl;vm_operation(&cl);}// Phase 2: Concurrent Mark{ZStatTimer timer(ZPhaseConcurrentMark);ZHeap::heap()->mark(true /* initial */);}// Phase 3: Pause Mark End{ZMarkEndClosure cl;while (!vm_operation(&cl)) {// Phase 3.5: Concurrent Mark ContinueZStatTimer timer(ZPhaseConcurrentMarkContinue);ZHeap::heap()->mark(false /* initial */);}}// Phase 4: Concurrent Process Non-Strong References{ZStatTimer timer(ZPhaseConcurrentProcessNonStrongReferences);ZHeap::heap()->process_non_strong_references();}// Phase 5: Concurrent Reset Relocation Set{ZStatTimer timer(ZPhaseConcurrentResetRelocationSet);ZHeap::heap()->reset_relocation_set();}// Phase 6: Concurrent Destroy Detached Pages{ZStatTimer timer(ZPhaseConcurrentDestroyDetachedPages);ZHeap::heap()->destroy_detached_pages();}// Phase 7: Pause Verifyif (VerifyBeforeGC || VerifyDuringGC || VerifyAfterGC) {ZVerifyClosure cl;vm_operation(&cl);}// Phase 8: Concurrent Select Relocation Set{ZStatTimer timer(ZPhaseConcurrentSelectRelocationSet);ZHeap::heap()->select_relocation_set();}// Phase 9: Concurrent Prepare Relocation Set{ZStatTimer timer(ZPhaseConcurrentPrepareRelocationSet);ZHeap::heap()->prepare_relocation_set();}// Phase 10: Pause Relocate Start{ZRelocateStartClosure cl;vm_operation(&cl);}// Phase 11: Concurrent Relocate{ZStatTimer timer(ZPhaseConcurrentRelocated);ZHeap::heap()->relocate();}
}

3. 引用

OpenJDK 12 源代码

OpenJDK ZGC 源码分析(六)GC回收相关推荐

  1. 【转】ABP源码分析六:依赖注入的实现

    ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...

  2. motan源码分析六:客户端与服务器的通信层分析

    本章将分析motan的序列化和底层通信相关部分的代码. 1.在上一章中,有一个getrefers的操作,来获取所有服务器的引用,每个服务器的引用都是由DefaultRpcReferer来创建的 pub ...

  3. 谷歌chrome浏览器的源码分析(六)

    消息的流通过程,是一个不同类相互交流的过程,如果不了解这个过程,根本就不知道这些类是怎么样相互协作的.由于上一次说到ViewHostMsg_RequestResource消息已经发送出来,它的处理过徎 ...

  4. tcp/ip 协议栈Linux内核源码分析六 路由子系统分析一路由缓存

    内核版本:3.4.39 收到报文或者发送报文的时候都需要查找路由表,频繁的路由表查找操作时需要耗费一部分CPU的,Linux提供了路由缓存来减少路由表的查询,路由缓存由hash表组织而成,路由缓存的初 ...

  5. Heritrix源码分析(六) Heritrix的文件结构分析

    本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.javaeye.com/blog/642618        欢迎加入Heritrix群(QQ): 109148319 ...

  6. 集合框架源码分析六之堆结构的实现(PriorityQueue)

    /** * * 优先队列是用了一种叫做堆的高效的数据结构, * 堆是用二叉树来描述的,对任意元素n,索引从0开始,如果有子节点的话,则左子树为 * 2*n+1,右子树为2*(n+1). * 以堆实现的 ...

  7. Tomcat源码分析(六)--日志记录器和国际化

    本系列转载自 http://blog.csdn.net/haitao111313/article/category/1179996 日志记录器挺简单的,没有很多东西,最主要的就是一个Logger接口: ...

  8. OpenJDK16 ZGC 源码分析

    动手点关注 干货不迷路 

  9. rnnlm源码分析 六

    系列前言 参考文献: RNNLM - Recurrent Neural Network  Language Modeling Toolkit(点此阅读) Recurrent neural networ ...

最新文章

  1. 为什么阿里巴巴这一次能扛得起 11 亿的流量?
  2. sklearn SVM(支持向量机)模型使用RandomSearchCV获取最优参数及可视化​​​​​​​
  3. 杭电oj2035c语言答案,杭电oj 2035
  4. centos7开启tcp6_Centos7下配置IPV6
  5. java Unicode转UTF-8代码
  6. python图像对比度增强图片清晰度_Python 图像对比度增强的几种方法(小结)
  7. 【题解专栏】南华大学19级软卓选拔赛题解
  8. 如何通过OCJP认证考试
  9. OBS推流工具使用说明
  10. Redis 官方可视化工具,高颜值,功能太强大!
  11. 本地HTML打不开 总打开360页面,彻底解决IE浏览器打不开网页时自动跳转到hao.360.cn导航页的问题-网络教程与技术 -亦是美网络...
  12. KDJ指标公式的应用要则是什么KDJ指标公式的使用技巧是什么
  13. 沉淀 2017,记录不平凡的一年!
  14. 计算机的基本组成和工作原理
  15. 按照之前的标题来看,这应该是...第四天(你以为是第三天的总结吗?图样图森破....
  16. 01 牛刀小试【PAT B1012】数字分类
  17. React Native与原生的图片交互问题
  18. 如何计算近似纳什均衡_澳洲计算机网络安全课程之-莫纳什大学硕士课程
  19. 数据库的登录密码忘记时,我们应该怎么办??
  20. HTTP笔记1:网络模型与TCP协议

热门文章

  1. java 农历节日 转公历日期_公历农历互相转换的Java日历工具类
  2. 第二批计算机专业有哪些学校,第二批!初试科目大调整,又有院校发通知,参考书、大纲都改啦!...
  3. //众神云集、群魔乱舞、以一抵百、砥砺前行//18640 扩号匹配问题
  4. Prometheus TSDB (Part 3): Memory Mapping of Head Chunks from Disk
  5. 基于Mapabc API的周边查询应用
  6. Linux命令初步-羽飞作品
  7. ETL (数据仓库技术)
  8. The Merge 过后,没有以太坊 2.0,只有共识层
  9. RedHat AS 4 下安装千千静国庆版4.6.0
  10. 《缠中说禅108课》55:买之前戏,卖之高潮