G1垃圾收集 - Mixed GC:
- 初始标记阶段 - Initial Mark
- 并发标记阶段 - Concurrent Mark
- 最终标记阶段 - Remark
- 清理阶段 - Clean Up
并发标记阶段 - Concurrent Mark
特性:
- 并发 - 与Mutator并发进行
- 并发阶段Mutator产生的新的引用或引用的更新,会被SATB的写屏障记录下来
- 以初始标记的根出发进行深度扫描
- 标记过程可以被Young GC打断
并发标记步骤:
- markFromRoots从根开始扫描标记
- 创建并发标记任务类 CMConcurrentMarkingTask
- 循环执行标记任务do_marking_step
- 处理satb缓冲区drain_satb_buffers、处理本地队列drain_local_queue、处理全局栈drain_global_stack
- process_grey_object根据nextMarkBitMap中标记的对象,针对每个对象的field递归并发标记、即染灰
结果: 标记出整个堆的存活对象,统计存活数量
源码分析:
并发标记源码在:concurrentMark.cpp
void ConcurrentMark::markFromRoots() {
//重置溢出启动标记标志
_restart_for_overflow = false;
force_overflow_conc()->init();
//获取并行标记线程
_parallel_marking_threads = calc_parallel_marking_threads();
uint active_workers = MAX2(1U, parallel_marking_threads());
//设置并行任务结束符
set_concurrency_and_phase(active_workers, true );
//创建任务类CMConcurrentMarkingTask 执行并发标记
CMConcurrentMarkingTask markingTask(this, cmThread());
//根据并行策略执行
if (use_parallel_marking_threads()) {
_parallel_workers->set_active_workers((int)active_workers);
_parallel_workers->run_task(&markingTask);
} else {
markingTask.work(0);
}
print_stats();
}
我们继续追CMConcurrentMarkingTask 的work方法:
- 处理SATB 缓存
- 根据已经标记的分区nextBitMap位图对象进行处理,针对每个已标记对象的每个field进行递归并发标记
public:void work(uint worker_id) {
ResourceMark rm;
//当发生同步时,进行等待
SuspendibleThreadSet::join();
//根据work_id 读取并发标记任务
CMTask* the_task = _cm->task(worker_id);
if (!_cm->has_aborted()) {
do {
// 可以通过参数设置并发标记目标时间,默认值10ms,标识并发标记在10ms内完成
double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
//开始执行并发标记
the_task->do_marking_step(mark_step_duration_ms,//超时时间
true ,
false );
......
//清理溢出标记
_cm->clear_has_overflown();
_cm->do_yield_check(worker_id);
......
//循环结束条件 : 1、并发标记终止 2、并发标记任务终止
} while (!_cm->has_aborted() && the_task->has_aborted());
}
}
};
我们继续追 do_marking_step 方法:
//执行标记任务
void CMTask::do_marking_step(double time_target_ms,//标记时间
bool do_termination,
bool is_serial) {
//G1 回收策略
G1CollectorPolicy* g1_policy = _g1h->g1_policy();
_claimed = true;
//是否偷其他线程任务处理的标志
bool do_stealing = do_termination && !is_serial;
//获取标记目标时间
double diff_prediction_ms = g1_policy->get_new_prediction(&_marking_step_diffs_ms);
_time_target_ms = time_target_ms - diff_prediction_ms;
_words_scanned = 0;
_refs_reached = 0;
recalculate_limits();
// 清除并发任务终止的flag 和其他flag
clear_has_aborted();
_has_timed_out = false;
_draining_satb_buffers = false;
++_calls;
//闭包 后面用
CMBitMapClosure bitmap_closure(this, _cm, _nextMarkBitMap);
G1CMOopClosure cm_oop_closure(_g1h, _cm, this);
set_cm_oop_closure(&cm_oop_closure);
//溢出、则任务终止
if (_cm->has_overflown()) {
set_has_aborted();
}
//处理satb缓冲区
drain_satb_buffers();
//处理本地队列
drain_local_queue(true);
//处理全局栈
drain_global_stack(true);
do {
if (!has_aborted() && _curr_region != NULL) {
update_region_limit();
//MemRegion是新增的对象,从finger开始到结束全部开始标记
MemRegion mr = MemRegion(_finger, _region_limit);
//region为空,放弃处理
if (mr.is_empty()) {
giveup_current_region();
regular_clock_call();
//如果是大对象 并且 是该对象的最后一个分区
} else if (_curr_region->isHumongous() && mr.start() == _curr_region->bottom()) {
//如果对象已经被标记 ,对象需置灰处理
if (_nextMarkBitMap->isMarked(mr.start())) {
BitMap::idx_t offset = _nextMarkBitMap->heapWordToOffset(mr.start());
//处理对象的field指向的对象,形成递归
bitmap_closure.do_bit(offset);
}
//如果对象未被标记、直接结束本分区
giveup_current_region();
regular_clock_call();
//处理本分区标记对象,递归
} else if (_nextMarkBitMap->iterate(&bitmap_closure, mr)) {
giveup_current_region();
regular_clock_call();
} else {
HeapWord* new_finger = _nextMarkBitMap->nextObject(_finger);
if (new_finger >= _region_limit) {
giveup_current_region();
} else {
move_finger_to(new_finger);
}
}
}
//处理本地队列
drain_local_queue(true);
//处理全局栈
drain_global_stack(true);
while (!has_aborted() && _curr_region == NULL && !_cm->out_of_regions()) {
//获取一个region
HeapRegion* claimed_region = _cm->claim_region(_worker_id);
if (claimed_region != NULL) {
statsOnly( ++_regions_claimed );
//将新的region加载到标记任务
setup_for_region(claimed_region);
}
regular_clock_call();
}
//region为空或处理完
} while ( _curr_region != NULL && !has_aborted());
if (!has_aborted()) {
//处理satb缓冲区
drain_satb_buffers();
}
//处理本地队列
drain_local_queue(false);
//处理全局栈
drain_global_stack(false);
if (do_stealing && !has_aborted()) {
while (!has_aborted()) {
oop obj;
statsOnly( ++_steal_attempts );
if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) {
statsOnly( ++_steals );
scan_object(obj);
drain_local_queue(false);
drain_global_stack(false);
} else {
break;
}
}
}
if (do_termination && !has_aborted()) {
if (_cm->force_overflow()->should_force()) {
_cm->set_has_overflown();
regular_clock_call();
}
}
//执行中止操作
if (do_termination && !has_aborted()) {
_termination_start_time_ms = os::elapsedVTime() * 1000.0;
bool finished = (is_serial || _cm->terminator()->offer_termination(this));
double termination_end_time_ms = os::elapsedVTime() * 1000.0;
_termination_time_ms += termination_end_time_ms - _termination_start_time_ms;
//中止成功
if (finished) {
if (_worker_id == 0) {
if (concurrent()) {
_cm->clear_concurrent_marking_in_progress();
}
}
} else {//中止失败
set_has_aborted();
statsOnly( ++_aborted_termination );
}
}
//清除闭包
set_cm_oop_closure(NULL);
double end_time_ms = os::elapsedVTime() * 1000.0;
double elapsed_time_ms = end_time_ms - _start_time_ms;
_step_times_ms.add(elapsed_time_ms);
//收尾工作
if (has_aborted()) {
statsOnly( ++_aborted );
//判断是否超时
if (_has_timed_out) {
double diff_ms = elapsed_time_ms - _time_target_ms;
_marking_step_diffs_ms.add(diff_ms);
}
//判断全局栈是否溢出
if (_cm->has_overflown()) {
if (!is_serial) {
_cm->enter_first_sync_barrier(_worker_id);
}
statsOnly( ++_aborted_overflow );
clear_region_fields();
if (!is_serial) {
_cm->enter_second_sync_barrier(_worker_id);
}
}
}
_claimed = false;
}
继续追处理satb方法drain_satb_buffers,最终会调用 deal_with_reference:
//处理对象引用
inline void CMTask::deal_with_reference(oop obj) {
increment_refs_reached();
HeapWord* objAddr = (HeapWord*) obj;
if (_g1h->is_in_g1_reserved(objAddr)) {
//判断是否被NTAMS标记
if (!_nextMarkBitMap->isMarked(objAddr)) {
HeapRegion* hr = _g1h->heap_region_containing_raw(obj);
if (!hr->obj_allocated_since_next_marking(obj)) {
make_reference_grey(obj, hr);
}
}
}
}
主要工作在 make_reference_grey
inline void CMTask::make_reference_grey(oop obj, HeapRegion* hr) {
//对对象进行标记和计数
if (_cm->par_mark_and_count(obj, hr, _marked_bytes_array, _card_bm)) {
HeapWord* global_finger = _cm->finger();
if (is_below_finger(obj, global_finger)) {
if (obj->is_typeArray()) {
//对对象标记的同时处理每个字段、对每个field进行标记处理
process_grey_object(obj);
} else {
push(obj);
}
}
}
}
真真真真真真。。。不错的文章 ->>>>>>>>>>>>>>G1并发标记过程观点不错的文章



