Repository navigation
g1 G1_Main_Marker
ceragon edited this page Dec 7, 2021
·
3 revisions
- 声明位于g1ConcurrentMarkThread.cpp中
G1ConcurrentMarkThread::G1ConcurrentMarkThread(G1ConcurrentMark* cm) :
ConcurrentGCThread(),
_cm(cm),
_state(Idle),
_phase_manager_stack(),
_vtime_accum(0.0),
_vtime_mark_accum(0.0) {
set_name("G1 Main Marker");
create_and_start();
}- 在 create_and_start 方法中会启动线程
- 线程的run方法如下
void ConcurrentGCThread::run() {
initialize_in_thread();
wait_for_universe_init();
run_service();
terminate();
}- run方法会调用 run_service() 方法,内容如下:
void G1ConcurrentMarkThread::run_service() {
while (!should_terminate()) {
sleep_before_next_cycle();
if (should_terminate()) {
break;
}
_cm->concurrent_cycle_start();
_cm->scan_root_regions();
for (uint iter = 1; !_cm->has_aborted(); ++iter) {
_cm->mark_from_roots();
if (_cm->has_aborted()) {
break;
}
if (G1UseReferencePrecleaning) {
_cm->preclean();
}
if (G1UseReferencePrecleaning) {
_cm->preclean();
}
delay_to_keep_mmu(g1_policy, true /* remark */);
if (_cm->has_aborted()) {
break;
}
CMRemark cl(_cm);
VM_CGC_Operation op(&cl, "Pause Remark");
VMThread::execute(&op);
if (_cm->has_aborted()) {
break;
}
}
if (!_cm->has_aborted()) {
_cm->rebuild_rem_set_concurrently();
}
if (!_cm->has_aborted()) {
delay_to_keep_mmu(g1_policy, false /* cleanup */);
}
if (!_cm->has_aborted()) {
CMCleanup cl_cl(_cm);
VM_CGC_Operation op(&cl_cl, "Pause Cleanup");
VMThread::execute(&op);
}
if (!_cm->has_aborted()) {
_cm->cleanup_for_next_mark();
}
_cm->concurrent_cycle_end();
}
}- 上面的run_service() 方法会在 sleep_before_next_cycle() 处等待,其中 CGC_Lock 是一个Monitor,关于monitor的解析,详见 Monitor
void G1ConcurrentMarkThread::sleep_before_next_cycle() {
MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
while (!started() && !should_terminate()) {
CGC_lock->wait(Mutex::_no_safepoint_check_flag);
}
if (started()) {
set_in_progress();
}
}- 其中的 CGC_lock 会处于循环等待状态,直到被其他线程调用 CGC_lock -> notify() 来唤醒,唯一调用notify()的方法如下:
void G1CollectedHeap::do_concurrent_mark() {
MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
if (!_cm_thread->in_progress()) {
_cm_thread->set_started();
CGC_lock->notify();
}
}- 调用上面方法的位置整理如下:
G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
// 触发并发标记的先决条件是,当前不处在并发标记的状态(或者说当前的暂停不是由并发标记引起的)
bool should_start_conc_mark = collector_state()->in_initial_mark_gc();
if (should_start_conc_mark) {
do_concurrent_mark();
}
}- 调用上述的方法的位置有两个地方,但是如果想触发并发标记,只有下面一个地方
void VM_G1CollectForAllocation::doit() {
// 该值是通过 VM_G1CollectForAllocation 的构造方法赋值的
if (_should_initiate_conc_mark) {
bool res = g1h->g1_policy()->force_initial_mark_if_outside_cycle(_gc_cause);
// 如果处在并发标记循环中,则res返回 false,否则返回true
if (!res) {
return;
}
}
_pause_succeeded = g1h->do_collection_pause_at_safepoint(_target_pause_time_ms);
}- 虽然上面的方法出现了一个 _should_initiate_conc_mark 的标记,但其实不影响下面的 do_collection_pause_at_safepoint 方法触发并发标记。所以直接看doit()方法的触发方或者调用方
- 由doit 方法调用之前需要对 VM_G1CollectForAllocation 进行初始化,所以下面列出了调用构造函数的位置
- 位置1
- 可以看到 full_gc 和 _wb_young_gc 都有可能触发
void G1CollectedHeap::collect(GCCause::Cause cause) {
if (should_do_concurrent_full_gc(cause)) {
VM_G1CollectForAllocation op(0, /* word_size */
gc_count_before,
cause,
true, /* should_initiate_conc_mark */
g1_policy()->max_pause_time_ms());
VMThread::execute(&op);
} else if (GCLocker::should_discard(cause, gc_count_before)) {
return;
} else {
if (cause == GCCause::_gc_locker || cause == GCCause::_wb_young_gc
DEBUG_ONLY(|| cause == GCCause::_scavenge_alot)) {
VM_G1CollectForAllocation op(0, /* word_size */
gc_count_before,
cause,
false, /* should_initiate_conc_mark */
g1_policy()->max_pause_time_ms());
VMThread::execute(&op);
}
}
// 另外一处的 should_initiate_conc_mark 为false,就不看了
}- 位置2
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::execute(&op);
}- 关于位置一,尝试分配大对象空间时,有可能触发
HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
}- 关于位置二, 尝试分配大对象空间或者尝试分配空间的时候
HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
if (should_try_gc) {
result = do_collection_pause(word_size, gc_count_before, &succeeded,
GCCause::_g1_humongous_allocation);
}
}HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size) {
if (should_try_gc) {
result = do_collection_pause(word_size, gc_count_before, &succeeded,
GCCause::_g1_inc_collection_pause);
}
}