Skip to content

g1 G1_Main_Marker

ceragon edited this page Dec 7, 2021 · 3 revisions

G1 Main Marker

声明

  1. 声明位于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();
}
  1. 在 create_and_start 方法中会启动线程

run 方法

  1. 线程的run方法如下
void ConcurrentGCThread::run() {
  initialize_in_thread();
  wait_for_universe_init();
  run_service();
  terminate();
}
  1. 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();
    }
}

触发方式

  1. 上面的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();
    }
}
  1. 其中的 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();
    }
}
  1. 调用上面方法的位置整理如下:
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();
    }
}
  1. 调用上述的方法的位置有两个地方,但是如果想触发并发标记,只有下面一个地方
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);
}
  1. 虽然上面的方法出现了一个 _should_initiate_conc_mark 的标记,但其实不影响下面的 do_collection_pause_at_safepoint 方法触发并发标记。所以直接看doit()方法的触发方或者调用方
  2. 由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);
}
  1. 关于位置一,尝试分配大对象空间时,有可能触发
HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
    
}
  1. 关于位置二, 尝试分配大对象空间或者尝试分配空间的时候
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);    
    }
}

Clone this wiki locally