Skip to content

g1 region AdaptiveRegion

ceragon edited this page Feb 1, 2022 · 6 revisions

G1 young region 大小

相关代码

以下代码是用户线程申请分配一个新的年轻代 region,如果超过年轻代的极限就会申请失败。而极限值就是 _young_list_target_length,后续的讨论会围绕这个值展开。

bool G1Policy::should_allocate_mutator_region() const {
  uint young_list_length = _g1h->young_regions_count();
  uint young_list_target_length = _young_list_target_length;
  return young_list_length < young_list_target_length;
}

_young_list_target_length

_young_list_target_length 的唯一赋值位置如下,需要查看两个事情。1、该方法的调用链.2、young_list_target_lengths() 内容是什么

uint G1Policy::update_young_list_target_length(size_t rs_lengths) {
  YoungTargetLengths young_lengths = young_list_target_lengths(rs_lengths);
  // —————————————————————————————————————————————
  _young_list_target_length = young_lengths.first;
  // —————————————————————————————————————————————
  return young_lengths.second;
}

young_list_target_lengths() 内容

主体内容如下:

G1Policy::YoungTargetLengths G1Policy::young_list_target_lengths(size_t rs_lengths) const {
  YoungTargetLengths result;
  // survivor 区的当前 region 长度
  const uint base_min_length = _g1h->survivor_regions_count();
  // —————————————————————————— 相关解读在下面 ————————————————————————————————————————
  // 这里返回的是期望的最小年轻代的 region 个数
  uint desired_min_length = calculate_young_list_desired_min_length(base_min_length);
  // ——————————————————————————————————————————————————————————————————————————————
  // 当前实际的年轻代最小 region 个数
  uint absolute_min_length = base_min_length + MAX2(_g1h->eden_regions_count(), (uint)1);
  // 以最大的为准
  desired_min_length = MAX2(desired_min_length, absolute_min_length);
  uint desired_max_length = calculate_young_list_desired_max_length();
  uint young_list_target_length = 0;
  if (adaptive_young_list_length()) {
    if (collector_state()->in_young_only_phase()) {
      young_list_target_length =
                        calculate_young_list_target_length(rs_lengths,
                                                           base_min_length,
                                                           desired_min_length,
                                                           desired_max_length);
    }
  } else {
    young_list_target_length = _young_list_fixed_length;
  }
  result.second = young_list_target_length;
  uint absolute_max_length = 0;
  if (_free_regions_at_end_of_collection > _reserve_regions) {
    absolute_max_length = _free_regions_at_end_of_collection - _reserve_regions;
  }
  if (desired_max_length > absolute_max_length) {
    desired_max_length = absolute_max_length;
  }
  if (young_list_target_length > desired_max_length) {
    young_list_target_length = desired_max_length;
  }
  if (young_list_target_length < desired_min_length) {
    young_list_target_length = desired_min_length;
  }
  result.first = young_list_target_length;
  return result;
}

calculate_young_list_desired_min_length()

uint G1Policy::calculate_young_list_desired_min_length(uint base_min_length) const {
    // 参数 base_min_length 是当前 survivor 区的个数
  uint desired_min_length = 0;
  // ————————— 相关解读如下 ———————————
  if (adaptive_young_list_length()) {
  // ————————————————————————————————
      // 如果年轻代大小是是自适应的
    // ——————— 如果 eden 区 region 的分配速率队列长度大于3 ———————————
    if (_analytics->num_alloc_rate_ms() > 3) {
    // ——————————————————————————————————————————————————————————
      // 记录当前时间
      double now_sec = os::elapsedTime();
      // —————————————————————————————————————————————————————————————
      double when_ms = _mmu_tracker->when_max_gc_sec(now_sec) * 1000.0;
      // —————————————————————————————————————————————————————————————
      double alloc_rate_ms = _analytics->predict_alloc_rate_ms();
      // 这里我认为是在计算 eden 区的大小,这取决于最大暂停时间,以及预测的 eden 区的分配速率
      desired_min_length = (uint) ceil(alloc_rate_ms * when_ms);
    }
  }
  desired_min_length += base_min_length;
  return MAX2(_young_gen_sizer.min_desired_young_length(), desired_min_length);
}

adaptive_young_list_length()

相关解读可以查看 adaptive_young_list_length,结论如下:

  • 在不设任何参数的情况下这个方法的返回值是 true
  • 年轻代的最小值是已分配 region 的 5%
  • 年轻代的最大值是已分配 region 的 60%

num_alloc_rate_ms()

相关解读可以查看 num_alloc_rate_ms,相关结论如下:

  • 这里面涉及到一个队列,队列里的每个元素都是年轻代里 eden 区 region 的分配速率
  • 这个方法的返回值是队列的大小,且队列的最大值是 10

when_max_gc_sec()

inline double when_max_gc_sec(double current_time) {
    return when_sec(current_time, max_gc_time());
}
double G1MMUTrackerQueue::when_sec(double current_time, double pause_time) {
    // 先说下两个参数,分别是当前的时间(单位s)和参数 MaxGCPauseMillis 的秒值(根据上面的方法 max_gc_time() 得知)
    // 根据上文,这里的 adjusted_pause_time 就是 max_gc_time()
  double adjusted_pause_time = (pause_time > max_gc_time()) ? max_gc_time() : pause_time;
  // 可以理解为如果立即开始暂停,最早什么时候结束
  double earliest_end = current_time + adjusted_pause_time;
  // _time_slice 是参数 GCPauseIntervalMillis 的秒值,默认值是 201ms == 0.201s
  // 根据 GCPauseIntervalMillis(暂停间隔) 算出来应该什么时候开始执行,limit 就是开始执行的时间
  double limit = earliest_end - _time_slice;
  
  double gc_time = calculate_gc_time(earliest_end);
  double diff = gc_time + adjusted_pause_time - max_gc_time();
  if (is_double_leq_0(diff))
    return 0.0;

  int index = _tail_index;
  while ( 1 ) {
    G1MMUTrackerQueueElem *elem = &_array[index];
    if (elem->end_time() > limit) {
      if (elem->start_time() > limit)
        diff -= elem->duration();
      else
        diff -= elem->end_time() - limit;
      if (is_double_leq_0(diff))
        return  elem->end_time() + diff + _time_slice - adjusted_pause_time - current_time;
    }
    index = trim_index(index+1);
    guarantee(index != trim_index(_head_index + 1), "should not go past head");
  }
}
double G1MMUTrackerQueue::calculate_gc_time(double current_time) {
  double gc_time = 0.0;
  // _time_slice = GCPauseIntervalMillis/1000, 
  double limit = current_time - _time_slice;
  for (int i = 0; i < _no_entries; ++i) {
    int index = trim_index(_tail_index + i);
    G1MMUTrackerQueueElem *elem = &_array[index];
    if (elem->end_time() > limit) {
      if (elem->start_time() > limit)
        gc_time += elem->duration();
      else
        gc_time += elem->end_time() - limit;
    }
  }
  return gc_time;
}

calculate_young_list_target_length()

uint G1Policy::calculate_young_list_target_length(size_t rs_lengths,
                                             uint base_min_length,
                                             uint desired_min_length,
                                             uint desired_max_length) const {
    uint min_young_length = desired_min_length - base_min_length;
    uint max_young_length = desired_max_length - base_min_length;

    const double target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0;
    const double survivor_regions_evac_time = predict_survivor_regions_evac_time();
    const size_t pending_cards = _analytics->predict_pending_cards();
    const size_t adj_rs_lengths = rs_lengths + _analytics->predict_rs_length_diff();
    const size_t scanned_cards = _analytics->predict_card_num(adj_rs_lengths, true /* for_young_gc */);
    const double base_time_ms =
            predict_base_elapsed_time_ms(pending_cards, scanned_cards) +
            survivor_regions_evac_time;
    const uint available_free_regions = _free_regions_at_end_of_collection;
    const uint base_free_regions =
            available_free_regions > _reserve_regions ? available_free_regions - _reserve_regions : 0;

    G1YoungLengthPredictor p(collector_state()->mark_or_rebuild_in_progress(),
                             base_time_ms,
                             base_free_regions,
                             target_pause_time_ms,
                             this);
    if (p.will_fit(min_young_length)) {
        if (p.will_fit(max_young_length)) {
            min_young_length = max_young_length;
        } else {
            uint diff = (max_young_length - min_young_length) / 2;
            while (diff > 0) {
                uint young_length = min_young_length + diff;
                if (p.will_fit(young_length)) {
                    min_young_length = young_length;
                } else {
                    max_young_length = young_length;
                }
                diff = (max_young_length - min_young_length) / 2;
            }
        }
    } else {
    }
    return base_min_length + min_young_length;
}

Clone this wiki locally