Repository navigation
g1 evacuation_Young_GC_Condition
ceragon edited this page Jan 1, 2022
·
6 revisions
下面的代码都有省略,省略的原因是为了突出显示和 Young GC 触发条件有关的内容
相关代码
HeapWord *G1CollectedHeap::attempt_allocation_slow(size_t word_size) {
HeapWord *result = NULL;
for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
bool should_try_gc;
uint gc_count_before;
{
MutexLockerEx x(Heap_lock);
// 如果获取到 Heap_lock 会进入到这里
// 下面代码会尝试在 heap 的 eden 区申请一块内存,大小是 word_size。
// 如果现有的 eden 区不满足分配,会尝试申请激活一个新的 eden region。
// 能否申请成功,取决于一些条件
result = _allocator->attempt_allocation_locked(word_size);
if (result != NULL) {
return result;
}
// 说明当前的 eden 区满了,所以走到了这里
// TODO: GCLocker 这个还没弄明白,但可以确认一点,为真的概率不大
// 我猜一下下面的逻辑。如果上一次 Young GC 被 GCLocker 打断了
// 而且还满足了临时扩充 eden 区的条件,会走下面的强制分配方法
if (GCLocker::is_active_and_needs_gc() && g1_policy()->can_expand_young_list()) {
result = _allocator->attempt_allocation_force(word_size);
if (result != NULL) {
return result;
}
}
should_try_gc = !GCLocker::needs_gc();
gc_count_before = total_collections();
}
// 如果上一次的 Young GC 没有被 GCLocker 打断,则这里为真
if (should_try_gc) {
bool succeeded;
// ————————————————————————————————————— 同步执行一次 GC ——————————————————————————————————
result = do_collection_pause(word_size, gc_count_before, &succeeded, GCCause::_g1_inc_collection_pause);
// ————————————————————————————————————————————————————————————————————————————————————————————————————
if (result != NULL) {
return result;
}
// GC 执行成功了,但依然没有足够空间分配 word_size 的大小
if (succeeded) {
return NULL;
}
} else {
// GCLockerRetryAllocationCount 的默认值是 2
if (gclocker_retry_count > GCLockerRetryAllocationCount) {
return NULL;
}
GCLocker::stall_until_clear();
gclocker_retry_count += 1;
}
size_t dummy = 0;
// 尝试普通分配,以下是官方解释
// 如果我们没有成功调度一次 GC(因为另一个线程打败了我们)或者我们由于 GC 锁定器而停止,我们可以到达这里。
// 在任何一种情况下,我们都应该重试分配尝试,以防另一个线程成功执行收集并回收足够的空间。
// 我们在这里进行第一次尝试(不持有 Heap_lock),后续尝试将在下一次循环迭代开始时(在获取 Heap_lock 之后)。
result = _allocator->attempt_allocation(word_size, word_size, &dummy);
if (result != NULL) {
return result;
}
}
return NULL;
}路径
- 下面方法调用了触发 Young GC 的方法。如果再反查下面方法的调用方法,会看到了两个方法。后面介绍了
inline HeapWord* G1CollectedHeap::attempt_allocation(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) {
HeapWord* result = _allocator->attempt_allocation(min_word_size, desired_word_size, actual_word_size);
if (result == NULL) {
// 分配失败
*actual_word_size = desired_word_size;
// 尝试慢分配 (因为分配过程涉及到锁,甚至有引发 GC 的可能)
result = attempt_allocation_slow(desired_word_size);
// ————————————————————————————————————————————————
}
}代码
- 相关代码如下
HeapWord* G1CollectedHeap::allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) {
// 在这里调用了 G1CollectedHeap::attempt_allocation() 方法
return attempt_allocation(min_size, requested_size, actual_size);
// ——————————————————————————————————————————————————————————————
}HeapWord *MemAllocator::allocate_inside_tlab_slow(Allocation &allocation) const {
HeapWord *mem = NULL;
ThreadLocalAllocBuffer &tlab = _thread->tlab();
// free() 表示 TLAB 的剩余空间,单位是字。
// refill_waste_limit() 表示 TLAB 空间浪费阈值。
// 阈值 = TLAB 大小 / TLABRefillWasteFraction。TLABRefillWasteFraction 的默认值是64
// 这里的意思可以理解为,如果 TLAB 分配不了了,但是可用空间在总 TLAB 空间的 1/64 之上,就为真
if (tlab.free() > tlab.refill_waste_limit()) {
return NULL;
}
// compute_size 是用来计算新的 TLAB 的大小。
// _word_size 是当前待创建对象的大小
size_t new_tlab_size = tlab.compute_size(_word_size);
// 为0只有一种情况,处于分配中的 eden region 无法容纳待创建对象
if (new_tlab_size == 0) {
return NULL;
}
// 在这里调用了 G1CollectedHeap::allocate_new_tlab() 方法
mem = _heap->allocate_new_tlab(min_tlab_size, new_tlab_size, &allocation._allocated_tlab_size);
// ——————————————————————————————————————————————————————————————————————————————————
if (mem == NULL) {
return NULL;
}
// 分配成功
return mem;
}HeapWord* MemAllocator::allocate_inside_tlab(Allocation& allocation) const {
// 先尝试在 TLAB 中分配
HeapWord* mem = _thread->tlab().allocate(_word_size);
if (mem != NULL) {
return mem;
}
// TLAB 空间不足,于是调用上面的那个方法
return allocate_inside_tlab_slow(allocation);
// ————————————————————————————————————————
}分支代码
HeapWord* G1CollectedHeap::mem_allocate(size_t word_size, bool* gc_overhead_limit_was_exceeded) {
if (is_humongous(word_size)) {
// 大对象走专属的分配流程
return attempt_allocation_humongous(word_size);
}
size_t dummy = 0;
// 调用上面的 G1CollectedHeap::attempt_allocation() 方法
return attempt_allocation(word_size, word_size, &dummy);
// ————————————————————————————————————————————————
}HeapWord *MemAllocator::allocate_outside_tlab(Allocation &allocation) const {
// 调用上面的 mem_allocate 方法
HeapWord *mem = _heap->mem_allocate(_word_size, &allocation._overhead_limit_exceeded);
// ——————————————————————————————————————————————————————————————————————————————————
if (mem == NULL) {
return mem;
}
return mem;
}解析
HeapWord* MemAllocator::mem_allocate(Allocation& allocation) const {
if (UseTLAB) {
// 默认 TLAB 是开启的
// 尝试在 TLAB 中分配对象,
// 如果 TLAB 空间不足就尝试在当前分配中的 eden region 分配
HeapWord* result = allocate_inside_tlab(allocation);
if (result != NULL) {
return result;
}
}
// 走到这里,说明 TLAB 和分配中的 eden region 没有足够空间
// 所谓的 outside 可以理解为非当前分配中的 eden region
// 所以这里是在向
return allocate_outside_tlab(allocation);
}oop MemAllocator::allocate() const {
oop obj = NULL;
{
// obj 是一个待分配空间的对象
Allocation allocation(*this, &obj);
// 执行 obj 对象的空间分配工作
HeapWord *mem = mem_allocate(allocation);
}
return obj;
}解析
inline HeapWord *G1Allocator::attempt_allocation_locked(size_t word_size) {
HeapWord *result = mutator_alloc_region()->attempt_allocation_locked(word_size);
return result;
}inline HeapWord* G1AllocRegion::attempt_allocation_locked(size_t word_size) {
return attempt_allocation_locked(word_size, word_size, &temp);
}inline HeapWord *G1AllocRegion::attempt_allocation_locked(size_t min_word_size,
size_t desired_word_size,
size_t *actual_word_size) {
// 通过加锁的方式在 _alloc_region 中申请一块新的 TLAB 空间
HeapWord *result = attempt_allocation(min_word_size, desired_word_size, actual_word_size);
if (result != NULL) {
return result;
}
// 尝试申请一个新的 eden region,并尝试在这块空间中分配。
// 第二个参数 false 表示申请 eden region 受最大值约束
result = new_alloc_region_and_allocate(desired_word_size, false /* force */);
if (result != NULL) {
return result;
}
return NULL;
}解析
inline HeapWord* G1Allocator::attempt_allocation_force(size_t word_size) {
return mutator_alloc_region()->attempt_allocation_force(word_size);
}inline HeapWord *G1AllocRegion::attempt_allocation_force(size_t word_size) {
// 本方法是在 G1AllocRegion 的子类 MutatorAllocRegion 中运行
// 第二个参数 true 表示无视 eden 区的上限,只要 heap 空间足够就分配新的 region
HeapWord *result = new_alloc_region_and_allocate(word_size, true /* force */);
if (result != NULL) {
return result;
}
return NULL;
}解析
HeapWord *G1CollectedHeap::do_collection_pause(size_t word_size,
uint gc_count_before,
bool *succeeded,
GCCause::Cause gc_cause) {
VM_G1CollectForAllocation op(word_size,
gc_count_before,
gc_cause,
false, /* should_initiate_conc_mark */
g1_policy()->max_pause_time_ms());
// 在 VMThread 中执行 GC 的逻辑,并且是同步执行
// 执行 GC 的时候会先进行 STW
VMThread::execute(&op);
HeapWord *result = op.result();
bool ret_succeeded = op.prologue_succeeded() && op.pause_succeeded();
*succeeded = ret_succeeded;
return result;
}解析
inline HeapWord* G1Allocator::attempt_allocation(size_t min_word_size,
size_t desired_word_size,
size_t* actual_word_size) {
HeapWord* result = mutator_alloc_region()->attempt_retained_allocation(min_word_size, desired_word_size, actual_word_size);
if (result != NULL) {
return result;
}
return mutator_alloc_region()->attempt_allocation(min_word_size, desired_word_size, actual_word_size);
}解读
HeapWord *G1AllocRegion::new_alloc_region_and_allocate(size_t word_size, bool force) {
HeapRegion *new_alloc_region = allocate_new_region(word_size, force);
if (new_alloc_region != NULL) {
new_alloc_region->reset_pre_dummy_top();
_used_bytes_before = new_alloc_region->used();
HeapWord *result = allocate(new_alloc_region, word_size);
OrderAccess::storestore();
update_alloc_region(new_alloc_region);
return result;
} else {
return NULL;
}
}