- 1.源码中WorkGang, GangWorker结构关系
SharedHeap的结构如下,在结构中含有成员FlexibleWorkGang* _workers;
class SharedHeap : public CollectedHeap {
friend class VMStructs;
friend class VM_GC_Operation;
friend class VM_CGC_Operation;
private:
// For claiming strong_roots tasks.
SubTasksDone* _process_strong_tasks;
protected:
……
// If we're doing parallel GC, use this gang of threads.
FlexibleWorkGang* _workers;
……
};
FlexibleWorkGang的继承关系如下
class FlexibleWorkGang: public WorkGang {
……
};
class WorkGang: public AbstractWorkGang {
……
Void run_task(AbstractGangTask* task);
……
};
class AbstractWorkGang: public CHeapObj {
// Here's the public interface to this class.
public:
// Constructor and destructor.
AbstractWorkGang(const char* name, bool are_GC_task_threads,
bool are_ConcurrentGC_threads);
~AbstractWorkGang();
// Run a task, returns when the task is done (or terminated).
virtual void run_task(AbstractGangTask* task) = 0;
// Stop and terminate all workers.
virtual void stop();
public:
// Debugging.
const char* name() const;
protected:
// Initialize only instance data.
const bool _are_GC_task_threads;
const bool _are_ConcurrentGC_threads;
// Printing support.
const char* _name;
// The monitor which protects these data,
// and notifies of changes in it.
Monitor* _monitor;
// The count of the number of workers in the gang.
int _total_workers;
// Whether the workers should terminate.
bool _terminate;
// The array of worker threads for this gang.
// This is only needed for cleaning up.
GangWorker** _gang_workers;
// The task for this gang.
AbstractGangTask* _task;
// A sequence number for the current task.
int _sequence_number;
// The number of started workers.
int _started_workers;
// The number of finished workers.
int _finished_workers;
};
GangWorker的结构如下
class GangWorker: public WorkerThread {
public:
// Constructors and destructor.
GangWorker(AbstractWorkGang* gang, uint id);
// The only real method: run a task for the gang.
virtual void run();
// Predicate for Thread
virtual bool is_GC_task_thread() const;
virtual bool is_ConcurrentGC_thread() const;
// Printing
void print_on(outputStream* st) const;
virtual void print() const { print_on(tty); }
protected:
AbstractWorkGang* _gang;
virtual void initialize();
virtual void loop();
public:
AbstractWorkGang* gang() const { return _gang; }
};
- 2. GC线程创建
GangWorker就是GC线程,那么它是如何创建起来的呢?
当虚拟机启动的时候,会进行一些初始化操作,我们看一看是通过怎样的路径创建GangWorker的。Trace信息如下所示
#0 0x00002adb4964bace in FlexibleWorkGang (this=0x48,
name=0xb00000000 <Address 0xb00000000 out of bounds>, workers=10971,
are_GC_task_threads=8, are_ConcurrentGC_threads=false)
at /home/chengtao/hotspot20/src/share/vm/utilities/workgroup.hpp:280
#1 0x00002adb4998e403 in SharedHeap (this=0x5903a430, policy_=0x5903a2f0)
at /home/chengtao/hotspot20/src/share/vm/memory/sharedHeap.cpp:76
#2 0x00002adb49731331 in GenCollectedHeap (this=0x5903a430, policy=0x5903a2f0)
at /home/chengtao/hotspot20/src/share/vm/memory/genCollectedHeap.cpp:76
#3 0x00002adb49a23f95 in Universe::initialize_heap ()
at /home/chengtao/hotspot20/src/share/vm/memory/universe.cpp:921
#4 0x00002adb49a243f8 in universe_init ()
at /home/chengtao/hotspot20/src/share/vm/memory/universe.cpp:781
#5 0x00002adb49767a52 in init_globals ()
at /home/chengtao/hotspot20/src/share/vm/runtime/init.cpp:98
#6 0x00002adb49a0e56a in Threads::create_vm (args=0x41964080,
canTryAgain=0x4196405b)
at /home/chengtao/hotspot20/src/share/vm/runtime/thread.cpp:3092
#7 0x00002adb497a181c in JNI_CreateJavaVM (vm=0x419640e0, penv=0x419640e8,
args=0x41964080)
at /home/chengtao/hotspot20/src/share/vm/prims/jni.cpp:3344
#8 0x00000000400035f8 in InitializeJVM ()
#9 0x000000004000206e in JavaMain ()
在WorkGang进行完成构造以后,会进行初始化,调用_workers->initialize_workers();在这个函数中,进行创建GangWorker,具体如下
//创建保存GangWork的指针数组
_gang_workers = NEW_C_HEAP_ARRAY(GangWorker*, total_workers());
// 创建_total_workers个GangWorker,实际上_total_workers是与ParallelGCThreads相等的,ParallelGCThreads这个值是根据cpu core计算出来的一个值
//每创建一个GangWorker就会立即启动这个线程
for (int worker = 0; worker < total_workers(); worker += 1) {
GangWorker* new_worker = allocate_worker(worker);
assert(new_worker != NULL, "Failed to allocate GangWorker");
_gang_workers[worker] = new_worker;
if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) {
vm_exit_out_of_memory(0, "Cannot create worker GC thread. Out of system resources.");
return false;
}
if (!DisableStartThread) {
os::start_thread(new_worker);
}
}
到此,Parallel GC线程就被创建完了,并启动。
- 3. Parallel GC线程是如何工作的
我们来看一下GangWorker的一些函数,可以看到,当GC线程被创建以后,首先会进行一些初始化工作,然后就进入到了loop函数中。仔细分析这个loop函数,可以发现,刚开始GC线程是进入wait状态的,等待被唤醒然后进行GC,接下来我们看一看GC线程是如何被唤醒的。
void GangWorker::run() {
initialize();
loop();
}
void GangWorker::initialize() {
this->initialize_thread_local_storage();
assert(_gang != NULL, "No gang to run in");
os::set_priority(this, NearMaxPriority);
if (TraceWorkGang) {
tty->print_cr("Running gang worker for gang %s id %d",
gang()->name(), id());
}
// The VM thread should not execute here because MutexLocker's are used
// as (opposed to MutexLockerEx's).
assert(!Thread::current()->is_VM_thread(), "VM thread should not be part"
" of a work gang");
}
void GangWorker::loop() {
int previous_sequence_number = 0;
Monitor* gang_monitor = gang()->monitor();
for ( ; /* !terminate() */; ) {
WorkData data;
int part; // Initialized below.
{
// Grab the gang mutex.
MutexLocker ml(gang_monitor);
// Wait for something to do.
// Polling outside the while { wait } avoids missed notifies
// in the outer loop.
gang()->internal_worker_poll(&data);
if (TraceWorkGang) {
tty->print("Polled outside for work in gang %s worker %d",
gang()->name(), id());
tty->print(" terminate: %s",
data.terminate() ? "true" : "false");
tty->print(" sequence: %d (prev: %d)",
data.sequence_number(), previous_sequence_number);
if (data.task() != NULL) {
tty->print(" task: %s", data.task()->name());
} else {
tty->print(" task: NULL");
}
tty->cr();
}
for ( ; /* break or return */; ) {
// Terminate if requested.
if (data.terminate()) {
gang()->internal_note_finish();
gang_monitor->notify_all();
return;
}
// Check for new work.
if ((data.task() != NULL) &&
(data.sequence_number() != previous_sequence_number)) {
gang()->internal_note_start();
gang_monitor->notify_all();
part = gang()->started_workers() - 1;
break;
}
// Nothing to do.
gang_monitor->wait(/* no_safepoint_check */ true);
gang()->internal_worker_poll(&data);
if (TraceWorkGang) {
tty->print("Polled inside for work in gang %s worker %d",
gang()->name(), id());
tty->print(" terminate: %s",
data.terminate() ? "true" : "false");
tty->print(" sequence: %d (prev: %d)",
data.sequence_number(), previous_sequence_number);
if (data.task() != NULL) {
tty->print(" task: %s", data.task()->name());
} else {
tty->print(" task: NULL");
}
tty->cr();
}
}
// Drop gang mutex.
}
if (TraceWorkGang) {
tty->print("Work for work gang %s id %d task %s part %d",
gang()->name(), id(), data.task()->name(), part);
}
assert(data.task() != NULL, "Got null task");
data.task()->work(part);
{
if (TraceWorkGang) {
tty->print("Finish for work gang %s id %d task %s part %d",
gang()->name(), id(), data.task()->name(), part);
}
// Grab the gang mutex.
MutexLocker ml(gang_monitor);
gang()->internal_note_finish();
// Tell the gang you are done.
gang_monitor->notify_all();
// Drop the gang mutex.
}
previous_sequence_number = data.sequence_number();
}
}
当需要进行GC的时候,以ParNew为例,会进入到ParNewGeneration::collect这个函数,这个函数中有这样一段代码
if (n_workers > 1) {
GenCollectedHeap::StrongRootsScope srs(gch);
workers->run_task(&tsk);
} else {
GenCollectedHeap::StrongRootsScope srs(gch);
tsk.work(0);
}
进行Parallel GC的时候,就会进入到workers->run_task(&tsk)这个函数中了。函数原型就是void WorkGang::run_task(AbstractGangTask* task);
在这个函数中有这样一段代码
// Initialize.
_task = task;
_sequence_number += 1;
_started_workers = 0;
_finished_workers = 0;
// Tell the workers to get to work.
monitor()->notify_all();
// Wait for them to be finished
while (finished_workers() < total_workers()) {
if (TraceWorkGang) {
tty->print_cr("Waiting in work gang %s: %d/%d finished sequence %d",
name(), finished_workers(), total_workers(),
_sequence_number);
}
monitor()->wait(/* no_safepoint_check */ true);
}
_task = NULL;
从代码中我们可以发现,monitor()->notify_all();就可以唤醒GC线程了,然后进入到wait状态,等待所有GC线程完成GC任务结束,然后退出。
- 4. 总结
总结起来很简单,就是初始时,WorkGang创建ParallelGCThreads个GC线程(GangWorker),这些GC线程处于wait状态。当进行Paralel GC的时候,WorkGang就会唤醒wait的GC线程,进行Parallel GC。WorkGang等待Parallel GC完成后返回。