Repository navigation
g1 region AdaptiveRegion
ceragon edited this page Feb 1, 2022
·
6 revisions
以下代码是用户线程申请分配一个新的年轻代 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 的唯一赋值位置如下,需要查看两个事情。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;
}主体内容如下:
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;
}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,结论如下:
- 在不设任何参数的情况下这个方法的返回值是 true
- 年轻代的最小值是已分配 region 的 5%
- 年轻代的最大值是已分配 region 的 60%
相关解读可以查看 num_alloc_rate_ms,相关结论如下:
- 这里面涉及到一个队列,队列里的每个元素都是年轻代里 eden 区 region 的分配速率
- 这个方法的返回值是队列的大小,且队列的最大值是 10
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;
}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;
}