Repository navigation
g1 region Adaptive_young_list_length
wangkaiwu edited this page Jan 11, 2022
·
3 revisions
- 该代码用于设置是否动态调整年轻代的大小,默认情况下是 true.以下情况会设置为 false。
- 当设置了参数
NewRatio参数,且生效 - 设置了
NewSize和MaxNewSize两个参数,且两个参数值一样时。
- 当设置了参数
- 在不设参数的情况洗,默认是自适应调整年轻代大小,范围如下:
- 最小值(同时也是初始大小)是 heap 当前已激活的 region 个数的 5%
- 最大值是 heap 当前已激活的 region 个数的 60%
class G1YoungGenSizer {
bool adaptive_young_list_length() const {
return _adaptive_size;
}
};过程
G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults),
// _adaptive_size 的默认值是 true,在 NewRatio 参数生效之后会设为 false
_adaptive_size(true),
_min_desired_young_length(0), _max_desired_young_length(0) {
// 参数 NewRatio 是否进行了设置, 默认值是 2
if (FLAG_IS_CMDLINE(NewRatio)) {
if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) {
// 如果设置了 NewSize 或 MaxNewSize,则 NewRatio 会被覆盖
log_warning(gc, ergo)("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio");
} else {
_sizer_kind = SizerNewRatio;
// 由于限定了年轻代的比例,所以大小无法自适应
// ————————————————————
_adaptive_size = false;
// ————————————————————
return;
}
}
if (FLAG_IS_CMDLINE(NewSize)) {
// 如果设置了初始的年轻代大小
// 计算一下应该初始分配多少个 region
_min_desired_young_length = MAX2((uint) (NewSize / HeapRegion::GrainBytes), 1U);
if (FLAG_IS_CMDLINE(MaxNewSize)) {
// 如果设置了最大的年轻代大小
// 计算一下最多有几个年轻代的 region
_max_desired_young_length = MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes), 1U);
// 当前的策略是设置了最大和初始年轻代大小
_sizer_kind = SizerMaxAndNewSize;
// 只要初始值和最大值不一样,则就是年轻代自适应大小
// —————————————————————————————————————————————————————————————————————
_adaptive_size = _min_desired_young_length != _max_desired_young_length;
// —————————————————————————————————————————————————————————————————————
} else {
// 仅设置了初始的年轻代大小
_sizer_kind = SizerNewSizeOnly;
}
} else if (FLAG_IS_CMDLINE(MaxNewSize)) {
// 计算一下最多有几个年轻代的 region
_max_desired_young_length = MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes), 1U);
// 策略是仅设置了最大年轻代大小
_sizer_kind = SizerMaxNewSizeOnly;
}
}当自适应启用时,且没有设置过 NewSize 或 MaxNewSize时,年轻代的初始 region 个数和最大 region 个数分别是多少呢?
- 相关计算的代码如下
void G1YoungGenSizer::recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length) {
switch (_sizer_kind) {
case SizerDefaults:
// 默认策略,也就是没有设置任何参数
*min_young_length = calculate_default_min_length(number_of_heap_regions);
*max_young_length = calculate_default_max_length(number_of_heap_regions);
break;
case SizerNewSizeOnly:
// 只设置了 NewSize,所以只需要计算最大个数
*max_young_length = calculate_default_max_length(number_of_heap_regions);
*max_young_length = MAX2(*min_young_length, *max_young_length);
break;
case SizerMaxNewSizeOnly:
// 只设置了 MaxNewSize,所以只需要计算初始个数
*min_young_length = calculate_default_min_length(number_of_heap_regions);
*min_young_length = MIN2(*min_young_length, *max_young_length);
break;
case SizerMaxAndNewSize:
// 最大和最小都设置了
break;
case SizerNewRatio:
// 设置了 NewRatio 参数,所以最大最小值都是一样的
*min_young_length = number_of_heap_regions / (NewRatio + 1);
*max_young_length = *min_young_length;
break;
}
}- 方法的第一个参数 number_of_heap_regions,从字面意思来看是当前 heap 的 region 个数,但还是要深究一下。下面先看下最小值和最大值的计算方法,最后看下 number_of_heap_regions 参数的来源.
最大值和最小值
下面的方法是计算初始大小的方法,参数 G1NewSizePercent 的默认值是 5
uint G1YoungGenSizer::calculate_default_min_length(uint new_number_of_heap_regions) {
// 当前总 region 个数的 5% 是年轻代的初始 region 个数
uint default_value = (new_number_of_heap_regions * G1NewSizePercent) / 100;
return MAX2(1U, default_value);
}下面的方法是计算最大个数的方法,参数G1MaxNewSizePercent 的默认值是 60
uint G1YoungGenSizer::calculate_default_max_length(uint new_number_of_heap_regions) {
// 当前 region 个数的 60% 是年轻代的最大 region 个数
uint default_value = (new_number_of_heap_regions * G1MaxNewSizePercent) / 100;
return MAX2(1U, default_value);
}number_of_heap_regions 参数来源
一共由两个地方调用
- adjust_max_new_size() 方法
void G1YoungGenSizer::adjust_max_new_size(uint number_of_heap_regions) {
uint temp = _min_desired_young_length;
uint result = _max_desired_young_length;
recalculate_min_max_young_length(number_of_heap_regions, &temp, &result);
}- heap_size_changed() 方法
void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) {
recalculate_min_max_young_length(new_number_of_heap_regions, &_min_desired_young_length, &_max_desired_young_length);
}下面分别对这两个调用展开讨论
可以看到在这个调用链下,number_of_heap_regions 的值是整个 heap 的最大 region 个数。
void G1Policy::init(G1CollectedHeap* g1h, G1CollectionSet* collection_set) {
_g1h = g1h;
_young_gen_sizer.adjust_max_new_size(_g1h->max_regions());
}以下代码是 heap_size_changed() 的内容,其中参数 new_number_of_regions 可以认为是当前已激活的 region 的个数.
void G1Policy::record_new_heap_size(uint new_number_of_regions) {
// 根据当前已激活的 region 个数来计算年轻代的最小值和最大值
_young_gen_sizer.heap_size_changed(new_number_of_regions);
}上述方法的调用共有三处,过于复杂暂时不去解读三个调用的内容.
bool G1CollectedHeap::expand(size_t expand_bytes, WorkGang* pretouch_workers, double* expand_time_ms) {
size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
aligned_expand_bytes = align_up(aligned_expand_bytes, HeapRegion::GrainBytes);
uint regions_to_expand = (uint)(aligned_expand_bytes / HeapRegion::GrainBytes);
uint expanded_by = _hrm.expand_by(regions_to_expand, pretouch_workers);
if (expanded_by > 0) {
g1_policy()->record_new_heap_size(num_regions());
}
}HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size) {
uint obj_regions = (uint) humongous_obj_size_in_regions(word_size);
if (first == G1_NO_HRM_INDEX) {
first = _hrm.find_contiguous_empty_or_unavailable(obj_regions);
if (first != G1_NO_HRM_INDEX) {
g1_policy()->record_new_heap_size(num_regions());
}
}
}void G1CollectedHeap::shrink_helper(size_t shrink_bytes) {
uint num_regions_to_remove = (uint)(shrink_bytes / HeapRegion::GrainBytes);
uint num_regions_removed = _hrm.shrink_by(num_regions_to_remove);
if (num_regions_removed > 0) {
g1_policy()->record_new_heap_size(num_regions());
}
}