HotSpot中CMS收集器通过牺牲系统吞吐量来实现响应速度优先。适合追求垃圾收集速度的服务器上。
使用-XX:+UseConcMarkSweepGC启用CMS。
hotspot/src/share/vm/runtime/init.cpp
jint init_globals() { jint status = universe_init();}
hotspot/src/share/vm/memory/universe.cpp
jint universe_init() { jint status = Universe::initialize_heap();}
hotspot/src/share/vm/memory/universe.cpp
jint Universe::initialize_heap() {
_collectedHeap = create_heap();
status = _collectedHeap->initialize();
}
hotspot/src/share/vm/memory/universe.cpp
使用UseConcMarkSweepGC策略创建堆,和Serial收集器一样使用分代堆GenCollectedHeap,收集策略为ConcurrentMarkSweepPolicy继承自分代策略GenCollectorPolicy
CollectedHeap* Universe::create_heap() {
if (UseParallelGC) {
return Universe::create_heap_with_policy<ParallelScavengeHeap, GenerationSizer>();
} else if (UseG1GC) {
return Universe::create_heap_with_policy<G1CollectedHeap, G1CollectorPolicy>();
} else if (UseConcMarkSweepGC) {
return Universe::create_heap_with_policy<GenCollectedHeap, ConcurrentMarkSweepPolicy>();
} else if (UseSerialGC) {
return Universe::create_heap_with_policy<GenCollectedHeap, MarkSweepPolicy>();
}
}
hotspot/src/share/vm/memory/universe.inline.hpp
策略模板函数
template <class Heap, class Policy>
CollectedHeap* Universe::create_heap_with_policy() {
Policy* policy = new Policy(); //创建收集策略 MarkSweepPolicy是GenCollectorPolicy的一种
policy->initialize_all();
return new Heap(policy); //创建分代堆具体来说就是GenCollectedHeap
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
分代堆创建WorkGang
GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) :
CollectedHeap(),...
{
//创建WorkGang来管理GC线程
if (UseConcMarkSweepGC) {
_workers = new WorkGang("GC Thread", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
_workers->initialize_workers();
} else {
// Serial GC does not use workers.
_workers = NULL;
}
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
创建CMSCollector
jint GenCollectedHeap::initialize() {
......
#if INCLUDE_ALL_GCS
// If we are running CMS, create the collector responsible
// for collecting the CMS generations.
if (collector_policy()->is_concurrent_mark_sweep_policy()) {
bool success = create_cms_collector();
}
#endif // INCLUDE_ALL_GCS
return JNI_OK;
}
hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp
初始化CMSCollector,创建YieldingFlexibleWorkGang管理CMS GC线程,创建后台常驻线程ConcurrentMarkSweepThread用于CMS后台垃圾收集
CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,...): ...
{
_cmsGen->cmsSpace()->set_collector(this);
_markBitMap.allocate(_span)//位图
_modUnionTable.allocate(_span);
_markStack.allocate(MarkStackSize)//标记栈
//多线程收集创建YieldingFlexibleWorkGang,管理CMS GC Thread
//为每个线程创建一个任务队列
if (ConcGCThreads > 1) {
_conc_workers = new YieldingFlexibleWorkGang("CMS Thread",ConcGCThreads, true);
_conc_workers->initialize_workers();
_task_queues = new OopTaskQueueSet(num_queues);
for (i = 0; i < num_queues; i++) {
PaddedOopTaskQueue *q = new PaddedOopTaskQueue();
_task_queues->register_queue(i, q);
}
for (i = 0; i < num_queues; i++) {
_task_queues->queue(i)->initialize();
_hash_seed[i] = 17; // copied from ParNew
}
}
}
// 后台长期运行的CMS线程,用于CMS后台垃圾收集
_cmsThread = ConcurrentMarkSweepThread::start(this);
}
hotspot/src/share/vm/gc/shared/generationSpec.cpp
创建对应的收集器分代类型,CMS收集器对应ParNewGeneration和ConcurrentMarkSweepGeneration分代
#if INCLUDE_ALL_GCS
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
#include "gc/cms/parNewGeneration.hpp"
#endif // INCLUDE_ALL_GCS
Generation* GenerationSpec::init(ReservedSpace rs, CardTableRS* remset) {
switch (name()) {
case Generation::DefNew:
return new DefNewGeneration(rs, init_size());
case Generation::MarkSweepCompact:
return new TenuredGeneration(rs, init_size(), remset);
#if INCLUDE_ALL_GCS
case Generation::ParNew:
return new ParNewGeneration(rs, init_size());
case Generation::ConcurrentMarkSweep: {
ConcurrentMarkSweepGeneration* g = NULL;
g = new ConcurrentMarkSweepGeneration(rs, init_size(), remset);
g->initialize_performance_counters();
return g;
}
#endif // INCLUDE_ALL_GCS
}
hotspot/src/share/vm/gc/cms/parNewGeneration.cpp
继承自串行收集器的年轻代DefNewGeneration
ParNewGeneration::ParNewGeneration(ReservedSpace rs, size_t initial_byte_size)
: DefNewGeneration(rs, initial_byte_size, "PCopy"),
{
//创建任务队列集合
_task_queues = new ObjToScanQueueSet(ParallelGCThreads);
//每一个收集线程对应一个队列
for (uint i = 0; i < ParallelGCThreads; i++) {
ObjToScanQueue *q = new ObjToScanQueue();
guarantee(q != NULL, "work_queue Allocation failure.");
_task_queues->register_queue(i, q);
}
//初始化任务队列
for (uint i = 0; i < ParallelGCThreads; i++) {
_task_queues->queue(i)->initialize();
}
}
hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp
同串行收集器一样继承自CardGeneration
ConcurrentMarkSweepGeneration::ConcurrentMarkSweepGeneration(
ReservedSpace rs, size_t initial_byte_size, CardTableRS* ct) :
CardGeneration(rs, initial_byte_size, ct),
_dilatation_factor(((double)MinChunkSize)/((double)(CollectedHeap::min_fill_size()))),
_did_compact(false)
{
HeapWord* bottom = (HeapWord*) _virtual_space.low();
HeapWord* end = (HeapWord*) _virtual_space.high();
//映射一块空间
_cmsSpace = new CompactibleFreeListSpace(_bts, MemRegion(bottom, end));
_cmsSpace->_old_gen = this;
_gc_stats = new CMSGCStats();
//为每一个线程创建一个CMSParGCThreadState
_par_gc_thread_states = NEW_C_HEAP_ARRAY(CMSParGCThreadState*, ParallelGCThreads, mtGC);
for (uint i = 0; i < ParallelGCThreads; i++) {
_par_gc_thread_states[i] = new CMSParGCThreadState(cmsSpace());
}
}
CMS的年轻代,老年代的分代,堆空间,收集策略和Serial收集器类似,不再赘述。参考Serial收集器一篇。
hotspot/src/share/vm/gc/cms/parNewGeneration.cpp
CMS的年轻代GC总是由收集策略决定,从模板策略函数collect进入。同Serial收集器一样,使用复制算法,将Eden空间的对象拷贝提升到to空间。各Closure分别对应各种对象遍历操作。主要流程:
void ParNewGeneration::collect(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab) {
//年轻代堆
GenCollectedHeap* gch = GenCollectedHeap::heap();
//自适应收集策略
AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy();
//多GC线程管理
WorkGang* workers = gch->workers();
//计算活跃的GC工作线程
uint active_workers =
AdaptiveSizePolicy::calc_active_workers(workers->total_workers(),
workers->active_workers(),
Threads::number_of_non_daemon_threads());
active_workers = workers->update_active_workers(active_workers);
//获取老年代
_old_gen = gch->old_gen();
//是否使用自适应策略
if (UseAdaptiveSizePolicy) {
set_survivor_overflow(false);
size_policy->minor_collection_begin();
}
age_table()->clear();
to()->clear(SpaceDecorator::Mangle);
gch->save_marks();
// Set the correct parallelism (number of queues) in the reference processor
ref_processor()->set_active_mt_degree(active_workers);
_preserved_marks_set.init(active_workers);
//并发任务终结者
ParallelTaskTerminator _term(active_workers, task_queues());
//线程任务状态集合
ParScanThreadStateSet thread_state_set(active_workers,
*to(), *this, *_old_gen, *task_queues(),
_overflow_stacks, _preserved_marks_set,
desired_plab_sz(), _term);
thread_state_set.reset(active_workers, promotion_failed());
{
StrongRootsScope srs(active_workers);
//创建任务
ParNewGenTask tsk(this, _old_gen, reserved().end(), &thread_state_set, &srs);
gch->rem_set()->prepare_for_younger_refs_iterate(true);
//派发任务
if (workers->total_workers() > 1) {
workers->run_task(&tsk);
} else {
tsk.work(0);
}
}
ReferenceProcessor* rp = ref_processor();
IsAliveClosure is_alive(this);
ScanWeakRefClosure scan_weak_ref(this);
KeepAliveClosure keep_alive(&scan_weak_ref);
ScanClosure scan_without_gc_barrier(this, false);
ScanClosureWithParBarrier scan_with_gc_barrier(this, true);
set_promo_failure_scan_stack_closure(&scan_without_gc_barrier);
EvacuateFollowersClosureGeneral evacuate_followers(gch,
&scan_without_gc_barrier, &scan_with_gc_barrier);
rp->setup_policy(clear_all_soft_refs);
// Can the mt_degree be set later (at run_task() time would be best)?
rp->set_active_mt_degree(active_workers);
ReferenceProcessorStats stats;
if (rp->processing_is_mt()) { //多线程
ParNewRefProcTaskExecutor task_executor(*this, *_old_gen, thread_state_set);
stats = rp->process_discovered_references(&is_alive, &keep_alive,
&evacuate_followers, &task_executor,
_gc_timer);
} else {
thread_state_set.flush();
gch->save_marks();
stats = rp->process_discovered_references(&is_alive, &keep_alive,
&evacuate_followers, NULL,
_gc_timer);
}
if (!promotion_failed()) { //提升失败
// Swap the survivor spaces.
eden()->clear(SpaceDecorator::Mangle);
from()->clear(SpaceDecorator::Mangle);
swap_spaces();
size_policy->reset_gc_overhead_limit_count();
adjust_desired_tenuring_threshold();
} else {
handle_promotion_failed(gch, thread_state_set);
}
}
老年代GC主要使用CMS算法。分为前后台收集方式。前台收集由用户触发。后台GC由常驻线程ConcurrentMarkSweepThread 定时等待触发。
jdk/src/java.base/share/native/libjava/Runtime.c
上一篇在触发GC的代码中我们循环创建大对象来触发GC,使用System.gc()来触发CMS的FullGC。
JNIEXPORT void JNICALL
Java_java_lang_Runtime_gc(JNIEnv *env, jobject this)
{
JVM_GC();
}
hotspot/src/share/vm/prims/jvm.cpp
可以使用DisableExplicitGC来禁止触发FullGC
JVM_ENTRY_NO_ENV(void, JVM_GC(void))
JVMWrapper("JVM_GC");
if (!DisableExplicitGC) {
Universe::heap()->collect(GCCause::_java_lang_system_gc);
}
JVM_END
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
void GenCollectedHeap::collect(GCCause::Cause cause) {
// Stop-the-world full collection.
collect(cause, OldGen);
......
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
void GenCollectedHeap::collect(GCCause::Cause cause, GenerationType max_generation) {
collect_locked(cause, max_generation);
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
void GenCollectedHeap::collect_locked(GCCause::Cause cause, GenerationType max_generation) {
{
MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back
VM_GenCollectFull op(gc_count_before, full_gc_count_before,
cause, max_generation);
VMThread::execute(&op); //触发FullGc
}
}
hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp
GC触发后将由收集策略转发到这里执行
void ConcurrentMarkSweepGeneration::collect(bool full,...)
{
collector()->collect(full, clear_all_soft_refs, size, tlab);
}
hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp
void CMSCollector::collect(bool full,...)
{
acquire_control_and_collect(full, clear_all_soft_refs);
}
hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp
使用同串行收集器老年代一样的收集算法
void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
....
GenMarkSweep::invoke_at_safepoint(ref_processor(), clear_all_soft_refs);
....
}
后台常驻线程ConcurrentMarkSweepThread启动后会一直循环检测GC条件,触发后台GC
void ConcurrentMarkSweepThread::run_service() {
while (!should_terminate()) {
sleepBeforeNextCycle();
if (should_terminate()) break;
GCIdMark gc_id_mark;
GCCause::Cause cause = _collector->_full_gc_requested ?
_collector->_full_gc_cause : GCCause::_cms_concurrent_mark;
_collector->collect_in_background(cause);
}
}
hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp
后台GC采用并发标记清除算法,流程如下:
void CMSCollector::collect_in_background(GCCause::Cause cause) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
size_t prev_used = _cmsGen->used();
switch (_collectorState) { //初始标记触发VM_CMS_Initial_Mark
case InitialMarking:
{
ReleaseForegroundGC x(this); //加锁
stats().record_cms_begin();
VM_CMS_Initial_Mark initial_mark_op(this);
VMThread::execute(&initial_mark_op);
}
break;
case Marking: // 并发标记
// initial marking in checkpointRootsInitialWork has been completed
markFromRoots()
break;
case Precleaning: //预清理
// marking from roots in markFromRoots has been completed
preclean();
break;
case AbortablePreclean: //可被终止的预清理
abortable_preclean();
break;
case FinalMarking: //重新标记
{
ReleaseForegroundGC x(this);
VM_CMS_Final_Remark final_remark_op(this);
VMThread::execute(&final_remark_op);
}
break;
case Sweeping: //并发清除
// final marking in checkpointRootsFinal has been completed
sweep();
case Resizing: {
{
ReleaseForegroundGC x(this); // 解锁
MutexLockerEx y(Heap_lock, Mutex::_no_safepoint_check_flag);
CMSTokenSync z(true); // not strictly needed.
if (_collectorState == Resizing) {
compute_new_size();
save_heap_summary();
_collectorState = Resetting;
}
}
break;
}
case Resetting: //并发重置状态等待下次CMS的触发
// CMS heap resizing has been completed
reset_concurrent();
MetaspaceGC::set_should_concurrent_collect(false);
stats().record_cms_end();
break;
case Idling:
default:
ShouldNotReachHere();
break;
}
}
}
CMS收集器将标记清除切分为数个阶段,其中一些阶段可与应用程序一起运行,这会占用一部分系统资源,导致系统吞吐量降低,需要STW的回收阶段用时变小了,这部分耗时相对减少了,所以系统的响应速度提升了。