《JVM G1源码分析和调优》 —3.3 慢速分配
3.3 慢速分配
当不能进行快速分配,就进入到慢速分配。实际上在TLAB中也有可能进入到慢速分配,就是我们前面提到的attempt_allocation,前面已经解释过。
这里的慢速分配是指在TLAB中经过努力分配还不能成功,再次进入慢速分配,我们来看一下这个更慢的慢速分配:
attempt_allocation尝试进行对象分配,如果成功则返回。值得注意的是在attempt_
allocation里面可能会进行垃圾回收,这里的垃圾回收是指增量的垃圾回收,主要是新生代或者混合收集,关于收集的内容将在下面的章节介绍,分配相关的代码在3.2节已经介绍过了,不再赘述。
如果大对象在attempt_allocation_humongous,直接分配的老生代。
如果分配不成功,则进行GC垃圾回收,注意这里的回收主要是Full GC,然后再分配。因为这里是分配的最后一步,所以进行几次不同的垃圾回收和尝试。主要代码在satisfy_failed_allocation中。
最终成功分配或者失败达到一定次数,则分配失败。
慢速分配代码如下所示:
HeapWord* G1CollectedHeap::mem_allocate(size_t word_size,
bool* gc_overhead_limit_was_exceeded) {
for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */;
try_count += 1) {
uint gc_count_before;
HeapWord* result = NULL;
if (!isHumongous(word_size)) {
result = attempt_allocation(word_size, &gc_count_before, &gclocker_
retry_count);
} else {
result = attempt_allocation_humongous(word_size, &gc_count_before,
&gclocker_retry_count);
}
if (result != NULL) return result;
// 进行最后的分配尝试,要做Full GC
VM_G1CollectForAllocation op(gc_count_before, word_size);
// 通过VMThread执行
VMThread::execute(&op);
if (op.prologue_succeeded() && op.pause_succeeded()) {
HeapWord* result = op.result();
if (result != NULL && !isHumongous(word_size))
dirty_young_block(result, word_size);
return result;
} else {
// 是否分配失败次数达到阈值
if (gclocker_retry_count > GCLockerRetryAllocationCount) return NULL;
}
}
ShouldNotReachHere();
return NULL;
}
3.3.1 大对象分配
大对象分配和TLAB中的慢速分配基本类似。唯一的区别就是对象大小不同。步骤主要:
尝试垃圾回收,这里主要是增量回收,同时启动并发标记。
尝试开始分配对象,对于大对象分为两类,一类是大于HeapRegionSize的一半,但是小于HeapRegionSize,即一个完整的堆分区可以保存,则直接从空闲列表直接拿一个堆分区,或者分配一个新的堆分区。如果是连续对象,则需要多个堆分区,思路同上,但是处理的时候需要加锁。
如果失败再次尝试垃圾回收,之后再分配。
最终成功分配或者失败达到一定次数,则分配失败。
大对象分配代码如下所示:
hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size,
uint* gc_count_before_ret,
uint* gclocker_retry_count_ret) {
// 尝试开始垃圾回收
if (g1_policy()->need_to_start_conc_mark("concurrent humongous allocation",
word_size)) {
collect(GCCause::_g1_humongous_allocation);
}
HeapWord* result = NULL;
for (int try_count = 1; /* we'll return */; try_count += 1) {
{
// 需要加锁
MutexLockerEx x(Heap_lock);
// 大对象分配
result = humongous_obj_allocate(word_size, AllocationContext::current());
if (result != NULL) return result;
if (GC_locker::is_active_and_needs_gc()) {
should_try_gc = false;
} else {
if (GC_locker::needs_gc()) {
should_try_gc = false;
} else {
// 可以继续执行GC
gc_count_before = total_collections();
should_try_gc = true;
}
}
}
if (should_try_gc) {
// 垃圾回收,增量回收
result = do_collection_pause(word_size, gc_count_before, &succeeded,
GCCause::_g1_humongous_allocation);
if (result != NULL) return result;
if (succeeded) {
// 稍后可以进行回收,可以先返回
MutexLockerEx x(Heap_lock);
*gc_count_before_ret = total_collections();
return NULL;
}
} else {
// 是否达到分配次数阈值
if (*gclocker_retry_count_ret > GCLockerRetryAllocationCount) {
MutexLockerEx x(Heap_lock);
*gc_count_before_ret = total_collections();
return NULL;
}
GC_locker::stall_until_clear();
(*gclocker_retry_count_ret) += 1;
}
}
ShouldNotReachHere();
return NULL;
}
- 点赞
- 收藏
- 关注作者
评论(0)