[KANMARS原创] - (四) 从JVM源码来理解GC线程是如何创建启动触发任务的
JVM中垃圾回收线程的创建
本文描述了垃圾回收线程的创建过程,和在gc过程中,垃圾回收线程的任务分配
垃圾回收线程是在代回收堆GenCollectedHeap的父类SharedHeap的构造方法中创建的,可见代码
\hotspot\src\share\vm\memory\shareHeap.cpp中
构造方法: SharedHeap::SharedHeap(CollectorPolicy policy_)
代码: FlexibleWorkGang _workers = new FlexibleWorkGang(“Parallel GC Threads”, ParallelGCThreads,true,false);
代码: _workers->initialize_workers();
在FlexibleWorkGang中即为垃圾回收线程的创建
构造方法: FlexibleWorkGang 设置_active_workers数量为ParallelGCThreads,默认为0,但是会根据gc策略和CPU数量进行修改参见函数Abstract_VM_Version::nof_parallel_worker_threads
父类构造方法: WorkGang 设置_total_workers = workers;
父类构造方法: AbstractWorkGang::AbstractWorkGang
_monitor = new Monitor(Mutex::leaf,”WorkGroup monitor”,are_GC_task_threads);
_terminate = false;
_task = NULL;
_sequence_number = 0;
_started_workers = 0;
_finished_workers = 0;
在_workers->initialize_workers();中即为worker的初始化,参见代码\hotspot\src\share\vm\utilities\Workgroup.cpp
调用: WorkGang::initialize_workers()
代码: if (are_ConcurrentGC_threads()) {
worker_type = os::cgc_thread; 判断是并发垃圾回收线程
} else {
worker_type = os::pgc_thread; 判断是否是并行垃圾回收线程
}
代码: for (int worker = 0; worker < total_workers(); worker += 1) {
GangWorker new_worker = allocate_worker(worker); 申请一个worker内存
代码: GangWorker new_worker = new GangWorker(this, which);
_gang_workers[worker] = new_worker;
os::create_thread(new_worker, worker_type) 创建一个worker线程
代码: \hotspot\src\os\linux\vm\Os_linux.cpp
代码: OSThread osthread = new OSThread(NULL, NULL);
代码: osthread->set_thread_type(thr_type);
代码: thread->set_osthread(osthread);
代码: pthread_t tid;
int ret = pthread_create(&tid, &attr, (void ()(void)) java_start, thread);
代码: os::start_thread(new_worker);
代码: OSThread osthread = thread->osthread();
代码: osthread->set_state(RUNNABLE);
代码: pd_start_thread(thread);
代码: sync_with_child->notify(); 触发os函数,即 java_start函数
调用: static void java_start(Thread thread)
代码: thread->run(); 此处的thread是在上步骤生成的GangWorker
调用: GangWorker.run()
调用: initialize(); 初始化一些信息
调用: loop(); 循环操作
代码: WorkData data;
代码: gang()->internal_worker_poll(&data); 此处的gang()是指FlexibleWorkGang,AbstractWorkGang::internal_worker_poll(WorkData data)
data->set_terminate(terminate());
data->set_task(task()); 此处的task为AbstractGangTask的子类,但是FlexibleWorkGang在构造的时候,没有指定task,因此为空
data->set_sequence_number(sequence_number());
代码: data.task()->work(part); 此处的task为AbstractGangTask的子类,
包括:CMConcurrentMarkingTask、G1ParFinalCountTask、G1ParNoteEndTask、G1ParScrubRemSetTask、CMRemarkTask、
CMSParRemarkTask、CMSRefEnqueueTaskProxy、ParRebuildRSTask、G1ParVerifyTask、G1ParTask、
G1ParCleanupCTTask、ParKnownGarbageTask、ParNewRefProcTaskProxy、ParNewRefEnqueueTaskProxy、ParNewGenTask
在concurrentmarksweep中使用的是CMSParRemarkTask和CMSRefEnqueueTaskProxy
在parnew中使用的是ParNewRefProcTaskProxy、ParNewRefEnqueueTaskProxy、ParNewGenTask
CMSParRemarkTask任务的位置
入口 CMSCollector::collect(bool full, bool clear_all_soft_refs, size_t size, bool tlab)
调用: CMSCollector::acquire_control_and_collect(bool full, bool clear_all_soft_refs)或者
调用: CMSCollector::do_mark_sweep_work(bool clear_all_soft_refs, CollectorState first_state, bool should_start_over) 或者 VM_CMS_Initial_Mark::doit()
调用: CMSCollector::collect_in_foreground(bool clear_all_soft_refs) 或者CMSCollector::do_CMS_operation(CMS_op_type op)
调用: CMSCollector::checkpointRootsFinal(bool asynch,bool clear_all_soft_refs, bool init_mark_was_synchronous)
调用: CMSCollector::checkpointRootsFinalWork(bool asynch,bool clear_all_soft_refs, bool init_mark_was_synchronous)
调用: CMSCollector::do_remark_parallel()
代码: CMSParRemarkTask tsk(this,cms_space, perm_space,n_workers, workers, task_queues());
代码: workers->run_task(&tsk);
代码: tsk.work(0);
从上可知,由某个操作,例如内存分配,触发一个收集内存垃圾的动作,进而调用了属于该堆的worker的runtask函数,将task进行执行操作,调用work函数。
我们从更细节的角度来看一下gc的触发与执行
从$$23123!@#$%^&@#$%^&(%$^&*() –》发生了惨剧,作者写了三个小时的内容,因为一个随意的关闭,丢失了一部分从java.c启动到创建VMTHREAD,到VMTHREAD的安全点通知,到执行collect_as_vm_thread到do_collection,到安全点的恢复……….的文档……
已经晚上12:54,还在等待隔壁的不靠谱系统发版,没有心情写了,听一会儿歌,明天写VMTHREAD的启动过程和垃圾回收过程。………………….