1. 简介
G1的YGC仅针对标记为新生代的Region进行回收,因此YGC花费的时间较少。
正如之前章节所介绍的,一个Region属于老年代还是新生代时动态的,每次YGC都会回收全部新生代Region,并在之后的内存分配流程中重新分配Region给新生代。
2. 代码分析
2.1 YGC的流程
YGC的流程如下:
- 首先STW,YGC全过程都在STW时进行,不需要考虑并发场景
- 选择CSet(Collection Set),YGC中CSet即为全部新生代Region
- 根扫描
- 更新RSet
- 深度复制更新对象到Survivor Region
- 重构RSet
- 释放CSet
- 大对象回收
- 动态扩展内存
- 动态调整新生代Region数量
- 启动并发标记,判断是否需要紧接着进行一次混合式GC
2.2 具体步骤介绍
2.2.1 根扫描
void work(uint worker_id) {
{
ResourceMark rm;
HandleMark hm;
ReferenceProcessor* rp = _g1h->ref_processor_stw();
G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
pss->set_ref_discoverer(rp);
double start_strong_roots_sec = os::elapsedTime();
_root_processor->evacuate_roots(pss, worker_id);
// We pass a weak code blobs closure to the remembered set scanning because we want to avoid
// treating the nmethods visited to act as roots for concurrent marking.
// We only want to make sure that the oops in the nmethods are adjusted with regard to the
// objects copied by the current evacuation.
_g1h->g1_rem_set()->oops_into_collection_set_do(pss, worker_id);
double strong_roots_sec = os::elapsedTime() - start_strong_roots_sec;
double term_sec = 0.0;
size_t evac_term_attempts = 0;
{
double start = os::elapsedTime();
G1ParEvacuateFollowersClosure evac(_g1h, pss, _queues, _terminator.terminator(), G1GCPhaseTimes::ObjCopy);
evac.do_void();
}
}
};
GC并行任务包括跟扫描、更新RSet、对象复制,主要逻辑在g1CollectedHeap.cpp G1ParTask类的work方法中;evacuate_roots为根扫描。
g1RootProcessor.cpp的evacuate_roots主要逻辑如下
void G1RootProcessor::evacuate_roots(G1ParScanThreadState* pss, uint worker_i) {
process_java_roots(closures, phase_times, worker_i);
process_vm_roots(closures, phase_times, worker_i);
process_string_table_roots(closures, phase_times, worker_i);
}
- 处理java根
- 处理jvm根
- 处理string table根
process_java_roots
void G1RootProcessor::process_java_roots(G1RootClosures* closures,
G1GCPhaseTimes* phase_times,
uint worker_i) {
// Iterating over the CLDG and the Threads are done early to allow us to
// first process the strong CLDs and nmethods and then, after a barrier,
// let the thread process the weak CLDs and nmethods.
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CLDGRoots, worker_i);
if (_process_strong_tasks.try_claim_task(G1RP_PS_ClassLoaderDataGraph_oops_do)) {
ClassLoaderDataGraph::roots_cld_do(closures->strong_clds(), closures->weak_clds());
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ThreadRoots, worker_i);
bool is_par = n_workers() > 1;
Threads::possibly_parallel_oops_do(is_par,