OpenJDK ZGC 源码分析(六)GC回收
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回收相关推荐
- 【转】ABP源码分析六:依赖注入的实现
ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...
- motan源码分析六:客户端与服务器的通信层分析
本章将分析motan的序列化和底层通信相关部分的代码. 1.在上一章中,有一个getrefers的操作,来获取所有服务器的引用,每个服务器的引用都是由DefaultRpcReferer来创建的 pub ...
- 谷歌chrome浏览器的源码分析(六)
消息的流通过程,是一个不同类相互交流的过程,如果不了解这个过程,根本就不知道这些类是怎么样相互协作的.由于上一次说到ViewHostMsg_RequestResource消息已经发送出来,它的处理过徎 ...
- tcp/ip 协议栈Linux内核源码分析六 路由子系统分析一路由缓存
内核版本:3.4.39 收到报文或者发送报文的时候都需要查找路由表,频繁的路由表查找操作时需要耗费一部分CPU的,Linux提供了路由缓存来减少路由表的查询,路由缓存由hash表组织而成,路由缓存的初 ...
- Heritrix源码分析(六) Heritrix的文件结构分析
本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.javaeye.com/blog/642618 欢迎加入Heritrix群(QQ): 109148319 ...
- 集合框架源码分析六之堆结构的实现(PriorityQueue)
/** * * 优先队列是用了一种叫做堆的高效的数据结构, * 堆是用二叉树来描述的,对任意元素n,索引从0开始,如果有子节点的话,则左子树为 * 2*n+1,右子树为2*(n+1). * 以堆实现的 ...
- Tomcat源码分析(六)--日志记录器和国际化
本系列转载自 http://blog.csdn.net/haitao111313/article/category/1179996 日志记录器挺简单的,没有很多东西,最主要的就是一个Logger接口: ...
- OpenJDK16 ZGC 源码分析
动手点关注 干货不迷路
- rnnlm源码分析 六
系列前言 参考文献: RNNLM - Recurrent Neural Network Language Modeling Toolkit(点此阅读) Recurrent neural networ ...
最新文章
- 为什么阿里巴巴这一次能扛得起 11 亿的流量?
- sklearn SVM(支持向量机)模型使用RandomSearchCV获取最优参数及可视化​​​​​​​
- 杭电oj2035c语言答案,杭电oj 2035
- centos7开启tcp6_Centos7下配置IPV6
- java Unicode转UTF-8代码
- python图像对比度增强图片清晰度_Python 图像对比度增强的几种方法(小结)
- 【题解专栏】南华大学19级软卓选拔赛题解
- 如何通过OCJP认证考试
- OBS推流工具使用说明
- Redis 官方可视化工具,高颜值,功能太强大!
- 本地HTML打不开 总打开360页面,彻底解决IE浏览器打不开网页时自动跳转到hao.360.cn导航页的问题-网络教程与技术
-亦是美网络...
- KDJ指标公式的应用要则是什么KDJ指标公式的使用技巧是什么
- 沉淀 2017,记录不平凡的一年!
- 计算机的基本组成和工作原理
- 按照之前的标题来看,这应该是...第四天(你以为是第三天的总结吗?图样图森破....
- 01 牛刀小试【PAT B1012】数字分类
- React Native与原生的图片交互问题
- 如何计算近似纳什均衡_澳洲计算机网络安全课程之-莫纳什大学硕士课程
- 数据库的登录密码忘记时,我们应该怎么办??
- HTTP笔记1:网络模型与TCP协议
热门文章
- java 农历节日 转公历日期_公历农历互相转换的Java日历工具类
- 第二批计算机专业有哪些学校,第二批!初试科目大调整,又有院校发通知,参考书、大纲都改啦!...
- //众神云集、群魔乱舞、以一抵百、砥砺前行//18640 扩号匹配问题
- Prometheus TSDB (Part 3): Memory Mapping of Head Chunks from Disk
- 基于Mapabc API的周边查询应用
- Linux命令初步-羽飞作品
- ETL (数据仓库技术)
- The Merge 过后,没有以太坊 2.0,只有共识层
- RedHat AS 4 下安装千千静国庆版4.6.0
- 《缠中说禅108课》55:买之前戏,卖之高潮