源码文件:/src/hotspot/share/gc/z/zDirector.cpp

一、回收策略

main入口函数:

  1. void ZDirector::run_service() {
  2. // Main loop
  3. while (_metronome.wait_for_tick()) {
  4. sample_allocation_rate();
  5. const GCCause::Cause cause = make_gc_decision();
  6. if (cause != GCCause::_no_gc) {
  7. ZCollectedHeap::heap()->collect(cause);
  8. }
  9. }
  10. }
ZMetronome::wait_for_tick 是zgc定义的一个循环时钟函数,sample_allocation_rate函数则用于rule_allocation_rate策略估算可能oom的时间。重点关注:make_gc_decision函数,在判断从make_gc_decision函数返回的结果不是no_gc后,zgc将进行一次gc。
 
make_gc_decision函数:
  1. GCCause::Cause ZDirector::make_gc_decision() const {
  2. // Rule 0: Timer
  3. if (rule_timer()) {
  4. return GCCause::_z_timer;
  5. }
  6.  
  7. // Rule 1: Warmup
  8. if (rule_warmup()) {
  9. return GCCause::_z_warmup;
  10. }
  11.  
  12. // Rule 2: Allocation rate
  13. if (rule_allocation_rate()) {
  14. return GCCause::_z_allocation_rate;
  15. }
  16.  
  17. // Rule 3: Proactive
  18. if (rule_proactive()) {
  19. return GCCause::_z_proactive;
  20. }
  21.  
  22. // No GC
  23. return GCCause::_no_gc;
  24. }
make_gc_decision一共提供了4种被动gc策略:
rule 1:固定间隔时间
通过配置ZCollectionInterval参数,可以控制zgc在一个固定的时间间隔进行gc,默认值为0,表示不采用该策略,否则则判断从上次gc到现在的时间间隔是否大于ZCollectionInterval秒,是则gc。源码如下:
  1. bool ZDirector::rule_timer() const {
  2. if (ZCollectionInterval == ) {
  3. // Rule disabled
  4. return false;
  5. }
  6.  
  7. // Perform GC if timer has expired.
  8. const double time_since_last_gc = ZStatCycle::time_since_last();
  9. const double time_until_gc = ZCollectionInterval - time_since_last_gc;
  10.  
  11. log_debug(gc, director)("Rule: Timer, Interval: %us, TimeUntilGC: %.3lfs",
  12. ZCollectionInterval, time_until_gc);
  13.  
  14. return time_until_gc <= ;
  15. }

rule 2:预热规则

is_warm函数判断gc次数是否已超过3次,是则不使用该策略。

注释说的很清楚,当gc次数少于3时,判断堆使用率达到10%/20%/30%时,使用该策略

  1. bool ZDirector::rule_warmup() const {
  2. if (is_warm()) {
  3. // Rule disabled
  4. return false;
  5. }
  6.  
  7. // Perform GC if heap usage passes 10/20/30% and no other GC has been
  8. // performed yet. This allows us to get some early samples of the GC
  9. // duration, which is needed by the other rules.
  10. const size_t max_capacity = ZHeap::heap()->current_max_capacity();
  11. const size_t used = ZHeap::heap()->used();
  12. const double used_threshold_percent = (ZStatCycle::ncycles() + ) * 0.1;
  13. const size_t used_threshold = max_capacity * used_threshold_percent;
  14.  
  15. log_debug(gc, director)("Rule: Warmup %.0f%%, Used: " SIZE_FORMAT "MB, UsedThreshold: " SIZE_FORMAT "MB",
  16. used_threshold_percent * , used / M, used_threshold / M);
  17.  
  18. return used >= used_threshold;
  19. }
  20.  
  21. bool ZDirector::is_warm() const {
  22. return ZStatCycle::ncycles() >= ;
  23. }
  24.  
  25. // 位置:ZStat.cpp
  26. uint64_t ZStatCycle::ncycles() {
  27. return _ncycles; // gc次数
  28. }

rule 3:分配速率预估

is_first函数判断如果是首次gc,则直接返回false。

ZAllocationSpikeTolerance默认值为2,分配速率策略采用正态分布模型预测内存分配速率,加上ZAllocationSpikeTolerance修正因子,可以覆盖超过99.9%的内存分配速率的可能性

  1. bool ZDirector::rule_allocation_rate() const {
  2. if (is_first()) {
  3. // Rule disabled
  4. return false;
  5. }
  6.  
  7. // Perform GC if the estimated max allocation rate indicates that we
  8. // will run out of memory. The estimated max allocation rate is based
  9. // on the moving average of the sampled allocation rate plus a safety
  10. // margin based on variations in the allocation rate and unforeseen
  11. // allocation spikes.
  12.  
  13. // Calculate amount of free memory available to Java threads. Note that
  14. // the heap reserve is not available to Java threads and is therefore not
  15. // considered part of the free memory.
  16. const size_t max_capacity = ZHeap::heap()->current_max_capacity();
  17. const size_t max_reserve = ZHeap::heap()->max_reserve();
  18. const size_t used = ZHeap::heap()->used();
  19. const size_t free_with_reserve = max_capacity - used;
  20. const size_t free = free_with_reserve - MIN2(free_with_reserve, max_reserve);
  21.  
  22. // Calculate time until OOM given the max allocation rate and the amount
  23. // of free memory. The allocation rate is a moving average and we multiply
  24. // that with an allocation spike tolerance factor to guard against unforeseen
  25. // phase changes in the allocate rate. We then add ~3.3 sigma to account for
  26. // the allocation rate variance, which means the probability is 1 in 1000
  27. // that a sample is outside of the confidence interval.
  28. const double max_alloc_rate = (ZStatAllocRate::avg() * ZAllocationSpikeTolerance) + (ZStatAllocRate::avg_sd() * one_in_1000);
  29. const double time_until_oom = free / (max_alloc_rate + 1.0); // Plus 1.0B/s to avoid division by zero
  30.  
  31. // Calculate max duration of a GC cycle. The duration of GC is a moving
  32. // average, we add ~3.3 sigma to account for the GC duration variance.
  33. const AbsSeq& duration_of_gc = ZStatCycle::normalized_duration();
  34. const double max_duration_of_gc = duration_of_gc.davg() + (duration_of_gc.dsd() * one_in_1000);
  35.  
  36. // Calculate time until GC given the time until OOM and max duration of GC.
  37. // We also deduct the sample interval, so that we don't overshoot the target
  38. // time and end up starting the GC too late in the next interval.
  39. const double sample_interval = 1.0 / ZStatAllocRate::sample_hz;
  40. const double time_until_gc = time_until_oom - max_duration_of_gc - sample_interval;
  41.  
  42. log_debug(gc, director)("Rule: Allocation Rate, MaxAllocRate: %.3lfMB/s, Free: " SIZE_FORMAT "MB, MaxDurationOfGC: %.3lfs, TimeUntilGC: %.3lfs",
  43. max_alloc_rate / M, free / M, max_duration_of_gc, time_until_gc);
  44.  
  45. return time_until_gc <= ;
  46. }
  47.  
  48. bool ZDirector::is_first() const {
  49. return ZStatCycle::ncycles() == ;
  50. }

rule 4:积极回收策略

通过ZProactive可启用积极回收策略,is_warm函数判断启用该策略必须是在预热之后(gc次数超过3次)

自上一次gc后,堆使用率达到xmx的10%或者已过了5分钟,这个参数是弥补第三个规则中没有覆盖的场景,从上述分析可以得到第三个条件更多的覆盖分配速率比较高的场景。

  1. bool ZDirector::rule_proactive() const {
  2. if (!ZProactive || !is_warm()) {
  3. // Rule disabled
  4. return false;
  5. }
  6.  
  7. // Perform GC if the impact of doing so, in terms of application throughput
  8. // reduction, is considered acceptable. This rule allows us to keep the heap
  9. // size down and allow reference processing to happen even when we have a lot
  10. // of free space on the heap.
  11.  
  12. // Only consider doing a proactive GC if the heap usage has grown by at least
  13. // 10% of the max capacity since the previous GC, or more than 5 minutes has
  14. // passed since the previous GC. This helps avoid superfluous GCs when running
  15. // applications with very low allocation rate.
  16. const size_t used_after_last_gc = ZStatHeap::used_at_relocate_end();
  17. const size_t used_increase_threshold = ZHeap::heap()->current_max_capacity() * 0.10; // 10%
  18. const size_t used_threshold = used_after_last_gc + used_increase_threshold;
  19. const size_t used = ZHeap::heap()->used();
  20. const double time_since_last_gc = ZStatCycle::time_since_last();
  21. const double time_since_last_gc_threshold = * ; // 5 minutes
  22. if (used < used_threshold && time_since_last_gc < time_since_last_gc_threshold) {
  23. // Don't even consider doing a proactive GC
  24. log_debug(gc, director)("Rule: Proactive, UsedUntilEnabled: " SIZE_FORMAT "MB, TimeUntilEnabled: %.3lfs",
  25. (used_threshold - used) / M,
  26. time_since_last_gc_threshold - time_since_last_gc);
  27. return false;
  28. }
  29.  
  30. const double assumed_throughput_drop_during_gc = 0.50; // 50%
  31. const double acceptable_throughput_drop = 0.01; // 1%
  32. const AbsSeq& duration_of_gc = ZStatCycle::normalized_duration();
  33. const double max_duration_of_gc = duration_of_gc.davg() + (duration_of_gc.dsd() * one_in_1000);
  34. const double acceptable_gc_interval = max_duration_of_gc * ((assumed_throughput_drop_during_gc / acceptable_throughput_drop) - 1.0);
  35. const double time_until_gc = acceptable_gc_interval - time_since_last_gc;
  36.  
  37. log_debug(gc, director)("Rule: Proactive, AcceptableGCInterval: %.3lfs, TimeSinceLastGC: %.3lfs, TimeUntilGC: %.3lfs",
  38. acceptable_gc_interval, time_since_last_gc, time_until_gc);
  39.  
  40. return time_until_gc <= ;
  41. }

最后,当所有策略都不满足时,返回_no_gc,表示不进行gc

二、回收过程

gc整个周期:

彩色指针示意图:

  • (STW)Pause Mark Start,开始标记,这个阶段只会标记(Mark0)由root引用的object,组成Root Set
  • Concurrent Mark,并发标记,从Root Set出发,并发遍历Root Set object的引用链并标记(Mark1)
  • (STW)Pause Mark End,检查是否已经并发标记完成,如果不是,需要进行多一次Concurrent Mark
  • Concurrent Process Non-Strong References,并发处理弱引用
  • Concurrent Reset Relocation Set
  • Concurrent Destroy Detached Pages
  • Concurrent Select Relocation Set,并发选择Relocation Set;
  • Concurrent Prepare Relocation Set,并发预处理Relocation Set
  • (STW)Pause Relocate Start,开始转移对象,依然是遍历root引用
  • Concurrent Relocate,并发转移,将需要回收的Page里的对象转移到Relocation Set,然后回收Page给系统重新利用

run_gc_cycle函数(/src/hotspot/share/gc/z/zDriver.cpp):

  1. void ZDriver::run_gc_cycle(GCCause::Cause cause) {
  2. ZDriverCycleScope scope(cause);
  3.  
  4. // Phase 1: Pause Mark Start
  5. {
  6. ZMarkStartClosure cl;
  7. vm_operation(&cl);
  8. }
  9.  
  10. // Phase 2: Concurrent Mark
  11. {
  12. ZStatTimer timer(ZPhaseConcurrentMark);
  13. ZHeap::heap()->mark();
  14. }
  15.  
  16. // Phase 3: Pause Mark End
  17. {
  18. ZMarkEndClosure cl;
  19. while (!vm_operation(&cl)) {
  20. // Phase 3.5: Concurrent Mark Continue
  21. ZStatTimer timer(ZPhaseConcurrentMarkContinue);
  22. ZHeap::heap()->mark();
  23. }
  24. }
  25.  
  26. // Phase 4: Concurrent Process Non-Strong References
  27. {
  28. ZStatTimer timer(ZPhaseConcurrentProcessNonStrongReferences);
  29. ZHeap::heap()->process_non_strong_references();
  30. }
  31.  
  32. // Phase 5: Concurrent Reset Relocation Set
  33. {
  34. ZStatTimer timer(ZPhaseConcurrentResetRelocationSet);
  35. ZHeap::heap()->reset_relocation_set();
  36. }
  37.  
  38. // Phase 6: Concurrent Destroy Detached Pages
  39. {
  40. ZStatTimer timer(ZPhaseConcurrentDestroyDetachedPages);
  41. ZHeap::heap()->destroy_detached_pages();
  42. }
  43.  
  44. // Phase 7: Concurrent Select Relocation Set
  45. {
  46. ZStatTimer timer(ZPhaseConcurrentSelectRelocationSet);
  47. ZHeap::heap()->select_relocation_set();
  48. }
  49.  
  50. // Phase 8: Concurrent Prepare Relocation Set
  51. {
  52. ZStatTimer timer(ZPhaseConcurrentPrepareRelocationSet);
  53. ZHeap::heap()->prepare_relocation_set();
  54. }
  55.  
  56. // Phase 9: Pause Relocate Start
  57. {
  58. ZRelocateStartClosure cl;
  59. vm_operation(&cl);
  60. }
  61.  
  62. // Phase 10: Concurrent Relocate
  63. {
  64. ZStatTimer timer(ZPhaseConcurrentRelocated);
  65. ZHeap::heap()->relocate();
  66. }
  67. }

未完待续

ZGC gc策略及回收过程-源码分析的更多相关文章

  1. (3.10)mysql基础深入——mysqld 服务器与客户端连接过程 源码分析【待写】

    (3.10)mysql基础深入——mysqld 服务器与客户端连接过程 源码分析[待写]

  2. Netty源码分析 (七)----- read过程 源码分析

    在上一篇文章中,我们分析了processSelectedKey这个方法中的accept过程,本文将分析一下work线程中的read过程. private static void processSele ...

  3. 设计模式(二十三)——策略模式(Arrays源码分析)

    1 编写鸭子项目,具体要求如下: 1) 有各种鸭子(比如 野鸭.北京鸭.水鸭等, 鸭子有各种行为,比如 叫.飞行等) 2) 显示鸭子的信息 2 传统方案解决鸭子问题的分析和代码实现 1) 传统的设计方 ...

  4. YARN(MapReduce 2)运行MapReduce的过程-源码分析

    这是我的分析,当然查阅书籍和网络.如有什么不对的,请各位批评指正.以下的类有的并不完全,只列出重要的方法. 如要转载,请注上作者以及出处. 一.源码阅读环境 需要安装jdk1.7.0版本及其以上版本, ...

  5. Flink中TaskManager端执行用户逻辑过程(源码分析)

    TaskManager接收到来自JobManager的jobGraph转换得到的TDD对象,启动了任务,在StreamInputProcessor类的processInput()方法中 通过一个whi ...

  6. Netty源码分析 (八)----- write过程 源码分析

    上一篇文章主要讲了netty的read过程,本文主要分析一下write和writeAndFlush. 主要内容 本文分以下几个部分阐述一个java对象最后是如何转变成字节流,写到socket缓冲区中去 ...

  7. HDFS dfsclient写文件过程 源码分析

    HDFS写入文件的重要概念 HDFS一个文件由多个block构成.HDFS在进行block读写的时候是以packet(默认每个packet为64K)为单位进行的.每一个packet由若干个chunk( ...

  8. spring启动component-scan类扫描加载过程---源码分析

    http://blog.csdn.net/xieyuooo/article/details/9089441#comments

  9. elasticsearch 5.5 query 过程 源码分析

    (1)请求 transfer to  任意node 节点 标记为coordinate node server入口函数 transportSearchAction doExecute方法 coordin ...

随机推荐

  1. NameNode数据存储

    HDFS架构图 HDFS原理 1)  三大组件 NameNode. DataNode .SecondaryNameNode 2)NameNode 存储元数据(文件名.创建时间.大小.权限.文件与blo ...

  2. Storm 系列(四)—— Storm 集群环境搭建

    一.集群规划 这里搭建一个 3 节点的 Storm 集群:三台主机上均部署 Supervisor 和 LogViewer 服务.同时为了保证高可用,除了在 hadoop001 上部署主 Nimbus ...

  3. 持续集成高级篇之Jenkins Pipeline 集成sonarqube

    系列目录 前面章节中我们讲到了Sonarqube的使用,其实Sonarqube获取msbuild结果主要是执行三个命令,开始标记,执行msbuild,结束标记,这些都是命令,是非常容易集成到我们ci流 ...

  4. 基于servlet的图书管理系统

    该项目是Java语言开发的图书管理系统,IDE采用eclipse,技术采用servlet,数据库使用mysql,前端页面采用bootstrap框架,简介美观. 系统具备基础的功能,读者可以注册登录,登 ...

  5. mysql:外键

    mysql:外键 转自:https://www.cnblogs.com/brucemengbm/p/6897410.html 一个班级的学生个人信息表: 什么是外键 在设计的时候,就给表1加入一个外键 ...

  6. python-re正则表达--持续更新

    | 模式          | 描述| |----              |----| | \w            | 匹配字母数字及下划线 | | \W           | 匹配非字母数 ...

  7. UGUI_关卡选项界面

    1.Image组件—“Source Image”,Set Native Size. 2.Image组件—“Image Type”——Sliced 编辑要放大缩小的图片,Sprite Editor,采用 ...

  8. MyBatis 3.5.2 新特性介绍

    1.MyBatis 最新版本 3.5.2 发布 MyBatis最新版本是:3.5.2,发布时间是:2019年7月15日 2.MyBatis 3.5.2 新特征介绍 我们知道,MyBatis 是支持定制 ...

  9. Linux入门基础之 下

    八.Linux 管道.重定向及文本处理 8.1.Linux 多命令协作:管道及重定向 8.1.1 开源文化 开源文化的核心理念之一就是不要重复发明轮子,很多的开源软件都是现有软件.代码.功能的重新组合 ...

  10. 第八届蓝桥杯java b组第三题

    标题:承压计算 X星球的高科技实验室中整齐地堆放着某批珍贵金属原料. 每块金属原料的外形.尺寸完全一致,但重量不同.金属材料被严格地堆放成金字塔形. 7                         ...