首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

Hotspot VM的Parallel GC 中 GC线程是怎么创建与工作的

2012-07-16 
Hotspot VM的Parallel GC 中 GC线程是如何创建与工作的1.源码中WorkGang, GangWorker结构关系SharedHeap的

Hotspot VM的Parallel GC 中 GC线程是如何创建与工作的
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完成后返回。

?

热点排行