Hotspot 垃圾回收之ConcurrentMarkSweepThread 源碼解析

   目錄

一、ConcurrentGCThread

二、SurrogateLockerThread

1、make

2、loop / manipulatePLL

三、ConcurrentMarkSweepThread

1、定義

2、start和構造方法

3、run

4、CMSSynchronousYieldRequest / asynchronous_yield_request / acknowledge_yield_request / should_yield

5、stop_icms / icms_wait / start_icms 

6、synchronize / desynchronize 

7、CMSTokenSync / CMSTokenSyncWithLocks

8、stop / threads_do


本篇博客講解在後臺執行CMS GC的ConcurrentMarkSweepThread的實現。

一、ConcurrentGCThread

     ConcurrentGCThread表示一個並行GC的線程,其定義在hotspot\src\share\vm\gc_implementation\shared\concurrentGCThread.hpp中,在NamedThread的基礎上添加了如下屬性:

  •   bool _should_terminate; //是否應該終止
  •   bool _has_terminated; //是否已經終止
  •   static int _CGC_flag; //GC的標誌

 _CGC_flag的取值有一個專門的枚舉,其定義如下:

 初始值爲CGC_nil,重點關注以下方法的實現:

  • create_and_start: 創建一個與之綁定的本地線程,設置優先級並啓動執行
  • initialize_in_thread:初始化ConcurrentGCThread本身,記錄線程棧基地址和大小,初始化TLAB等
  • wait_for_universe_init: 不斷循環等待Universe初始化完成
  • terminate: 終止當前ConcurrentGCThread的執行
ConcurrentGCThread::ConcurrentGCThread() :
  _should_terminate(false), _has_terminated(false) {
};

//用於創建關聯的本地線程並啓動
void ConcurrentGCThread::create_and_start() {
  //創建關聯的本地線程
  if (os::create_thread(this, os::cgc_thread)) {
    //設置優先級
    os::set_priority(this, NearMaxPriority);
    //DisableStartThread的默認值是false
    if (!_should_terminate && !DisableStartThread) {
      //啓動本地線程
      os::start_thread(this);
    }
  }
}

void ConcurrentGCThread::initialize_in_thread() {
  //記錄線程棧的基地址和大小
  this->record_stack_base_and_size();
  //初始化線程的本地存儲空間TLAB
  this->initialize_thread_local_storage();
  //設置JNIHandleBlock
  this->set_active_handles(JNIHandleBlock::allocate_block());
  // From this time Thread::current() should be working.
  assert(this == Thread::current(), "just checking");
}

void ConcurrentGCThread::wait_for_universe_init() {
  //獲取鎖CGC_lock
  MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
  //不斷循環,每隔200ms檢查一次universe是否初始化完成
  while (!is_init_completed() && !_should_terminate) {
    CGC_lock->wait(Mutex::_no_safepoint_check_flag, 200);
  }
}

void ConcurrentGCThread::terminate() {
  {
    //獲取鎖Terminator_lock
    MutexLockerEx mu(Terminator_lock,
                     Mutex::_no_safepoint_check_flag);
    _has_terminated = true;
    Terminator_lock->notify();
  }
  //解除跟本地線程的關聯,即終止本地線程
  ThreadLocalStorage::set_thread(NULL);
}

各方法的調用鏈如下:

 

 

 

從上述調用鏈可知,上述方法主要是G1算法在用。

二、SurrogateLockerThread

     SurrogateLockerThread表示一個用來操作Java Monitor鎖的線程,其定義也在concurrentGCThread.hpp中,其類繼承關係如下:

 其新增的屬性如下:

  •   SLT_msg_type  _buffer;  // 執行的動作類型
  •   Monitor       _monitor; // 負責同步的鎖
  •   BasicLock     _basicLock; // 實際未使用

 SLT_msg_type是一個枚舉,其定義如下:

重點關注以下方法的實現。

1、make

    make方法用於創建一個SurrogateLockerThread,將其與一個java.lang.Thread實例綁定,並啓動線程的執行,其實現如下:

SurrogateLockerThread* SurrogateLockerThread::make(TRAPS) {
  //獲取java_lang_Thread對應的Klass
  Klass* k =
    SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(),
                                      true, CHECK_NULL);
  instanceKlassHandle klass (THREAD, k);
  //thread_oop用於保存創建的線程實例
  instanceHandle thread_oop = klass->allocate_instance_handle(CHECK_NULL);

  const char thread_name[] = "Surrogate Locker Thread (Concurrent GC)";
  Handle string = java_lang_String::create_from_str(thread_name, CHECK_NULL);

  // Initialize thread_oop to put it into the system threadGroup
  Handle thread_group (THREAD, Universe::system_thread_group());
  JavaValue result(T_VOID);
  //調用構造方法 Thread(ThreadGroup group, String name) 創建一個Thread實例,結果保存在thread_oop中
  JavaCalls::call_special(&result, thread_oop,
                          klass,
                          vmSymbols::object_initializer_name(), //構造方法的方法名
                          vmSymbols::threadgroup_string_void_signature(), //構造方法的方法簽名
                          thread_group,//兩個參數
                          string,
                          CHECK_NULL);

  SurrogateLockerThread* res;
  {
    MutexLocker mu(Threads_lock);
    res = new SurrogateLockerThread();

    if (res == NULL || res->osthread() == NULL) {
      //res創建或者初始化失敗,通常是因爲內存不足導致的
      vm_exit_during_initialization("java.lang.OutOfMemoryError",
                                    "unable to create new native thread");
    }
    //將Thread實例同res關聯起來,底層是設置Thread的eetop屬性,該屬性就是關聯的C++線程對象的地址
    java_lang_Thread::set_thread(thread_oop(), res);
    //設置Thread實例的優先級
    java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
    //設置Thread實例的daemon屬性
    java_lang_Thread::set_daemon(thread_oop());
    //res與Thread實例關聯
    res->set_threadObj(thread_oop());
    //添加到Threads中保存的線程鏈表
    Threads::add(res);
    //啓動res線程的執行,即構造時傳入的_sltLoop方法
    Thread::start(res);
  }
  os::yield(); // This seems to help with initial start-up of SLT
  return res;
}

SurrogateLockerThread::SurrogateLockerThread() :
  JavaThread(&_sltLoop), //_sltLoop就是該線程執行的邏輯,即Run方法,JavaThread構造方法中會負責初始化相關屬性並創建關聯的本地線程
  _monitor(Mutex::nonleaf, "SLTMonitor"),
  _buffer(empty)
{}

static void _sltLoop(JavaThread* thread, TRAPS) {
  SurrogateLockerThread* slt = (SurrogateLockerThread*)thread;
  slt->loop();
}

其調用鏈如下:

Threads::create_vm中的調用如下圖:

 

無論CMS算法還是G1算法,SurrogateLockerThread指針都是靜態屬性,即只有一個SurrogateLockerThread實例。

2、loop / manipulatePLL

      manipulatePLL會修改_buffer屬性,然後釋放鎖等待loop方法執行完成相應的動作,loop方法不斷循環,根據_buffer屬性的值執行加鎖和釋放鎖,執行完成將buffer屬性重置爲empty,其實現如下:

void SurrogateLockerThread::loop() {
  //pll是pending list lock的簡稱
  BasicLock pll_basic_lock;
  SLT_msg_type msg;
  debug_only(unsigned int owned = 0;)

  while (/* !isTerminated() */ 1) {
    {
      MutexLocker x(&_monitor);
      assert(!SafepointSynchronize::is_at_safepoint(),
             "SLT is a JavaThread");
      //等待msg變成非empty
      while (_buffer == empty) {
        _monitor.notify();
        _monitor.wait();
      }
      msg = _buffer;
    }
    switch(msg) {
      case acquirePLL: {
        //獲取鎖
        InstanceRefKlass::acquire_pending_list_lock(&pll_basic_lock);
        debug_only(owned++;)
        break;
      }
      case releaseAndNotifyPLL: {
        assert(owned > 0, "Don't have PLL");
        //釋放鎖
        InstanceRefKlass::release_and_notify_pending_list_lock(&pll_basic_lock);
        debug_only(owned--;)
        break;
      }
      case empty:
      default: {
        guarantee(false,"Unexpected message in _buffer");
        break;
      }
    }
    {
      MutexLocker x(&_monitor);
      // Since we are a JavaThread, we can't be here at a safepoint.
      assert(!SafepointSynchronize::is_at_safepoint(),
             "SLT is a JavaThread");
      //將buffer重置爲empty     
      _buffer = empty;
      _monitor.notify();
    }
  }
  assert(!_monitor.owned_by_self(), "Should unlock before exit.");
}


void SurrogateLockerThread::manipulatePLL(SLT_msg_type msg) {
  //獲取鎖_monitor
  MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag);
  assert(_buffer == empty, "Should be empty");
  assert(msg != empty, "empty message");
  assert(!Heap_lock->owned_by_self(), "Heap_lock owned by requesting thread");
  //修改buffer
  _buffer = msg;
  while (_buffer != empty) {
    //notify會釋放鎖monitor,並喚醒等待該鎖的線程,此時loop方法會獲取鎖並根據msg執行相應的加鎖或者釋放鎖
    //執行完成再將buffer重置爲empty並喚醒等待的線程,調用manipulatePLL方法的線程就可以退出此方法了
    _monitor.notify();
    _monitor.wait(Mutex::_no_safepoint_check_flag);
  }
}

 loop方法就是SurrogateLockerThread執行的任務,manipulatePLL方法的調用鏈如下:

三、ConcurrentMarkSweepThread

1、定義

    ConcurrentMarkSweepThread表示CMS並行標記清理的線程,其定義在hotspot\src\share\vm\gc_implementation\concurrentMarkSweep\concurrentMarkSweepThread.hpp中,其類繼承關係如下:

 除ConcurrentMarkSweepThread外,其他三個類都是G1算法使用的。其新增的屬性如下:

  •   static ConcurrentMarkSweepThread*     _cmst; //全局的ConcurrentMarkSweepThread實例
  •   static CMSCollector*                  _collector; //關聯的CMSCollector
  •   static SurrogateLockerThread*         _slt; //關聯的SurrogateLockerThread
  •   static SurrogateLockerThread::SLT_msg_type _sltBuffer; //設置SurrogateLockerThread的buffer屬性
  •   static Monitor*                       _sltMonitor;
  •   static bool _should_terminate; //初始爲fase,當前線程是否應該終止
  •   static int _CMS_flag; //初始爲CMS_nil,實際就是0
  •   static char _pad_1[64 - sizeof(jint)];    // 用來避免高速緩存的緩存行共享問題,ConcurrentMarkSweepThread未使用
  •   static char _pad_2[64 - sizeof(jint)];    // 同上
  •   static volatile jint _pending_yields; //下面兩個屬性用來判斷GC線程是否應該讓出CPU的使用權,_pending_yields大於0則應該讓出CPU使用權
  •   static volatile jint _pending_decrements; //注意_pending_decrements是隻在iCMS模式下使用
  •   static volatile int _icms_disabled;   // 跟蹤iCMS模式開啓和關閉的計數器
  •   static volatile bool _should_run;     //初始爲false
  •   static volatile bool _should_stop;    //初始爲true

 _CMS_flag的取值是一個枚舉CMS_flag_type,其定義如下:

NoBits的值就是0,nth_bit就是把1右移多少位,即不同的flag Type對應不同位,所以不同的flag Type可以共存。重點關注以下方法的實現。

2、start和構造方法

       start方法調用構造方法創建一個ConcurrentMarkSweepThread實例,構造方法執行時會創建一個與之關聯的本地線程並啓動線程的執行,其實現如下:

ConcurrentMarkSweepThread::ConcurrentMarkSweepThread(CMSCollector* collector)
  : ConcurrentGCThread() {
  assert(UseConcMarkSweepGC,  "UseConcMarkSweepGC should be set");
  assert(_cmst == NULL, "CMS thread already created");
  _cmst = this;
  assert(_collector == NULL, "Collector already set");
  _collector = collector;
  //設置線程名
  set_name("Concurrent Mark-Sweep GC Thread");
  //創建關聯的線程
  if (os::create_thread(this, os::cgc_thread)) {
    int native_prio;
    //UseCriticalCMSThreadPriority表示使用一個特殊的優先級,默認爲false
    if (UseCriticalCMSThreadPriority) {
      native_prio = os::java_to_os_priority[CriticalPriority];
    } else {
      native_prio = os::java_to_os_priority[NearMaxPriority];
    }
    //設置線程優先級
    os::set_native_priority(this, native_prio);
    //DisableStartThread默認爲false
    if (!DisableStartThread) {
      //啓動線程,調用其run方法
      os::start_thread(this);
    }
  }
  _sltMonitor = SLT_lock;
  //CMSIncrementalMode表示是否開啓增量收集模式,適用於單核CPU場景,默認爲false
  assert(!CMSIncrementalMode || icms_is_enabled(), "Error");
}

ConcurrentMarkSweepThread* ConcurrentMarkSweepThread::start(CMSCollector* collector) {
  if (!_should_terminate) {
    assert(cmst() == NULL, "start() called twice?");
    //創建一個新的ConcurrentMarkSweepThread實例
    ConcurrentMarkSweepThread* th = new ConcurrentMarkSweepThread(collector);
    assert(cmst() == th, "Where did the just-created CMS thread go?");
    return th;
  }
  return NULL;
}

 其調用鏈如下:

3、run

     run方法就是ConcurrentMarkSweepThread的執行邏輯,會不斷循環等待,如果需要GC了則調用CMSCollector::collect_in_background方法執行GC,然後繼續下一次循環,直到_should_terminate屬性爲true,其實現如下:

void ConcurrentMarkSweepThread::run() {
  assert(this == cmst(), "just checking");
  //記錄線程棧基地址和大小
  this->record_stack_base_and_size();
  //初始化線程棧本地存儲內存
  this->initialize_thread_local_storage();
  //設置JNIHandleBlock
  this->set_active_handles(JNIHandleBlock::allocate_block());
  assert(this == Thread::current(), "just checking");
  //BindCMSThreadToCPU表示是否將CMSThread綁定到指定的CPU核上執行,默認爲false
  //CPUForCMSThread表示綁定的CPU核,默認是0,即第一個CPU核
  if (BindCMSThreadToCPU && !os::bind_to_processor(CPUForCMSThread)) {
    warning("Couldn't bind CMS thread to processor " UINTX_FORMAT, CPUForCMSThread);
  }
  {
    CMSLoopCountWarn loopX("CMS::run", "waiting for "
                           "Universe::is_fully_initialized()", 2);
    //獲取鎖
    MutexLockerEx x(CGC_lock, true);
    set_CMS_flag(CMS_cms_wants_token);
    //不斷循環等待,一次200ms,直到Universe完全初始化完畢
    while (!is_init_completed() && !Universe::is_fully_initialized() &&
           !_should_terminate) {
      CGC_lock->wait(true, 200);
      //增加循環次數,達到閾值了會打印warn日誌
      loopX.tick();
    }
    //不斷循環等待SurrogateLockerThread初始化完成,由Threads::create_vm方法負責初始化
    CMSLoopCountWarn loopY("CMS::run", "waiting for SLT installation", 2);
    while (_slt == NULL && !_should_terminate) {
      CGC_lock->wait(true, 200);
      loopY.tick();
    }
    clear_CMS_flag(CMS_cms_wants_token);
  }

  while (!_should_terminate) {
    //不斷等待直到需要執行GC
    sleepBeforeNextCycle();
    //如果_should_terminate爲true則終止循環
    if (_should_terminate) break;
    //獲取GC的原因
    GCCause::Cause cause = _collector->_full_gc_requested ?
      _collector->_full_gc_cause : GCCause::_cms_concurrent_mark;
    //在後臺執行GC  
    _collector->collect_in_background(false, cause);
  }
  //退出循環了,校驗_should_terminate爲true
  assert(_should_terminate, "just checking");
  //校驗是否可以終止
  verify_ok_to_terminate();
  // Signal that it is terminated
  {
    //獲取鎖Terminator_lock
    MutexLockerEx mu(Terminator_lock,
                     Mutex::_no_safepoint_check_flag);
    assert(_cmst == this, "Weird!");
    //cmst置爲NULL
    _cmst = NULL;
    Terminator_lock->notify();
  }
  //去掉CMSThread同本地線程的綁定
  ThreadLocalStorage::set_thread(NULL);
}

static ConcurrentMarkSweepThread* cmst()    { return _cmst; }

static bool set_CMS_flag(int b)           { return (_CMS_flag |= b) != 0;  }

static bool clear_CMS_flag(int b)         { return (_CMS_flag &= ~b) != 0; }

void ConcurrentMarkSweepThread::sleepBeforeNextCycle() {
  while (!_should_terminate) {
    if (CMSIncrementalMode) {
      //如果開啓增量模式
      //等待重新獲取CPU
      icms_wait();
      if(CMSWaitDuration >= 0) {
        wait_on_cms_lock_for_scavenge(CMSWaitDuration);
      }
      return;
    } else {
      //CMSWaitDuration表示CMSThread等待young gc的時間,默認值是2000
      if(CMSWaitDuration >= 0) {
        //等待直到超時或者需要一次Full GC或者已經完成了一次Full GC
        wait_on_cms_lock_for_scavenge(CMSWaitDuration);
      } else {
        //CMSCheckInterval表示CMSThread檢查是否應該執行GC的間隔時間,默認是1000ms
        //跟wait_on_cms_lock_for_scavenge相比,就是不會循環等待,只等待一次
        wait_on_cms_lock(CMSCheckInterval);
      }
    }
    //如果需要開始GC則終止循環
    if (_collector->shouldConcurrentCollect()) {
      return;
    }
  }
}

void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) {
  // Wait time in millis or 0 value representing infinite wait for a scavenge
  assert(t_millis >= 0, "Wait time for scavenge should be 0 or positive");

  GenCollectedHeap* gch = GenCollectedHeap::heap();
  double start_time_secs = os::elapsedTime();
  //計算結束時間
  double end_time_secs = start_time_secs + (t_millis / ((double) MILLIUNITS));

  //獲取當前的垃圾收集次數
  unsigned int before_count;
  {
    MutexLockerEx hl(Heap_lock, Mutex::_no_safepoint_check_flag);
    before_count = gch->total_collections();
  }

  unsigned int loop_count = 0;

  while(!_should_terminate) {
    double now_time = os::elapsedTime();
    long wait_time_millis;

    if(t_millis != 0) {
      //計算需要等待的時間
      wait_time_millis = (long) ((end_time_secs - now_time) * MILLIUNITS);
      if(wait_time_millis <= 0) {
        //超時了退出循環
        break;
      }
    } else {
      // No wait limit, wait if necessary forever
      wait_time_millis = 0;
    }

    // Wait until the next event or the remaining timeout
    {
      MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
      //如果需要終止CMSThread或者執行full GC則退出循環
      if (_should_terminate || _collector->_full_gc_requested) {
        return;
      }
      set_CMS_flag(CMS_cms_wants_token);   // to provoke notifies
      assert(t_millis == 0 || wait_time_millis > 0, "Sanity");
      //CGC_lock上等待最多wait_time_millis秒
      CGC_lock->wait(Mutex::_no_safepoint_check_flag, wait_time_millis);
      clear_CMS_flag(CMS_cms_wants_token);
      assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token),
             "Should not be set");
    }

    //CGC_lock上等待的線程被喚醒了,如果當前時間超過結束時間了
    if(t_millis != 0 && os::elapsedTime() >= end_time_secs) {
      //超時終止循環
      break;
    }

    //獲取此時的垃圾回收次數
    unsigned int after_count;
    {
      MutexLockerEx hl(Heap_lock, Mutex::_no_safepoint_check_flag);
      after_count = gch->total_collections();
    }

    if(before_count != after_count) {
      //如果垃圾回收次數變了,說明已經執行過一遍GC了,終止循環
      break;
    }

    //增加循環次數,一直不斷循環可能變成負值,等於0時說明循環的次數很大了,打印warning日誌
    if(++loop_count == 0) {
      warning("wait_on_cms_lock_for_scavenge() has looped %u times", loop_count - 1);
    }
  }
}

void ConcurrentMarkSweepThread::wait_on_cms_lock(long t_millis) {
  //獲取鎖CGC_lock
  MutexLockerEx x(CGC_lock,
                  Mutex::_no_safepoint_check_flag);
  if (_should_terminate || _collector->_full_gc_requested) {
    return;
  }
  set_CMS_flag(CMS_cms_wants_token);   // to provoke notifies
  //等待最長t_millis,期間可能被喚醒
  CGC_lock->wait(Mutex::_no_safepoint_check_flag, t_millis);
  clear_CMS_flag(CMS_cms_wants_token);
  assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token),
         "Should not be set");
}

#ifndef PRODUCT
void ConcurrentMarkSweepThread::verify_ok_to_terminate() const {
  assert(!(CGC_lock->owned_by_self() || cms_thread_has_cms_token() ||
           cms_thread_wants_cms_token()),
         "Must renounce all worldly possessions and desires for nirvana");
  _collector->verify_ok_to_terminate();
}
#endif

其中CMSLoopCountWarn的定義如下:

該類就是用來當循環次數達到閾值後就打印一行warning日誌 

4、CMSSynchronousYieldRequest / asynchronous_yield_request / acknowledge_yield_request / should_yield

     ConcurrentMarkSweepThread在執行過程中如果收到請求會讓出CPU的使用權限(yield動作),從而保證業務線程優先執行。有兩種請求方式,一種是同步的,適用於年輕代垃圾收集和老年代的內存分配,請求方會在執行業務邏輯前把_pending_yields加1,在執行業務邏輯後把_pending_yields減1,ConcurrentMarkSweepThread在執行相關GC邏輯時會判斷_pending_yields是否大於0,如果大於0則會讓當前線程休眠1ms,會不斷循環直到_pending_yields等於0爲止;另一種是異步的,在iCMS模式下使用,請求方通過調用stop_icms方法通知CMS Thread暫停執行,在iCMS_lock上等待,當請求方執行完相關邏輯會調用start_icms喚醒CMS Thread繼續執行,注意請求方調用stop_icms方法後並不會像第一種同步的請求方式立即通知CMS Thread業務操作執行完成。

     通過CMSSynchronousYieldRequest的構造和析構函數實現第一種同步請求;asynchronous_yield_request方法用於增加_pending_yields和_pending_decrements計數,acknowledge_yield_request用於減少_pending_yields和_pending_decrements計數,兩者都是通過原子指令操作;should_yield方法判斷當前CMS Thread是否需要讓出CPU使用權限,具體實現如下:

class CMSSynchronousYieldRequest: public StackObj {
 public:
  CMSSynchronousYieldRequest() {
    ConcurrentMarkSweepThread::increment_pending_yields();
  }
  ~CMSSynchronousYieldRequest() {
    ConcurrentMarkSweepThread::decrement_pending_yields();
  }
};

static void increment_pending_yields()   {
    Atomic::inc(&_pending_yields);
    assert(_pending_yields >= 0, "can't be negative");
  }
static void decrement_pending_yields()   {
    Atomic::dec(&_pending_yields);
    assert(_pending_yields >= 0, "can't be negative");
  }

static void asynchronous_yield_request() {
    assert(CMSIncrementalMode, "Currently only used w/iCMS");
    //同時原子的增加_pending_yields和_pending_decrements
    increment_pending_yields();
    Atomic::inc(&_pending_decrements);
    assert(_pending_decrements >= 0, "can't be negative");
  }

static void acknowledge_yield_request() {
    //獲取當值的值
    jint decrement = _pending_decrements;
    if (decrement > 0) {
      //decrement大於0說明開啓了iCMS模式
      assert(CMSIncrementalMode, "Currently only used w/iCMS");
      //注意 _pending_yields >= _pending_decrements,這裏相當於將decrement重置成0,_pending_decrements不一定是0
      Atomic::add(-decrement, &_pending_decrements);
      Atomic::add(-decrement, &_pending_yields);
      //在併發環境下decrement也可能不等於0
      assert(_pending_decrements >= 0, "can't be negative");
      assert(_pending_yields >= 0, "can't be negative");
    }
  }

  static bool should_yield()   { return _pending_yields > 0; }

  CMSSynchronousYieldRequest構造方法的調用鏈如下:

以allocate方法的調用爲例說明,如下:

 

另外三個方法的調用鏈如下:

 

 

5、stop_icms / icms_wait / start_icms 

     stop_icms方法用於通知CMS Thread暫停執行,在iCMS_lock上等待;icms_wait是CMS Thread使用的,會檢查是否需要暫停執行;start_icms方法用於通知CMS Thread重新開始執行,其實現如下:

void ConcurrentMarkSweepThread::stop_icms() {
  assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking");
  //獲取鎖iCMS_lock
  MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag);
  //_should_stop正常情況爲false
  if (!_should_stop) {
    //打印線程狀態
    trace_state("stop_icms");
    //將_should_stop置爲true
    _should_stop = true;
    _should_run = false;
    //增加計數器
    asynchronous_yield_request();
    //喚醒所有在iCMS_lock上等待的線程
    iCMS_lock->notify_all();
  }
}

void ConcurrentMarkSweepThread::icms_wait() {
  assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking");
  //如果調用了stop_icms則_should_stop變成true
  if (_should_stop && icms_is_enabled()) {
    //獲取鎖iCMS_lock
    MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag);
    trace_state("pause_icms");
    //停止CMS的計時器
    _collector->stats().stop_cms_timer();
    while(!_should_run && icms_is_enabled()) {
      //不斷循環等待,直到_should_run變成true
      iCMS_lock->wait(Mutex::_no_safepoint_check_flag);
    }
    //重新開啓計時器
    _collector->stats().start_cms_timer();
    //重置_should_stop
    _should_stop = false;
    trace_state("pause_icms end");
  }
}

void ConcurrentMarkSweepThread::start_icms() {
  assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking");
  //獲取鎖iCMS_lock
  MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag);
  trace_state("start_icms");
  //將_should_run置爲true
  _should_run = true;
  //喚醒所有等待的線程,判斷should_run變成true了重新開始執行
  iCMS_lock->notify_all();
}

其調用鏈如下:

 

 

 

6、synchronize / desynchronize 

      這兩個方法用來在ConcurrentMarkSweepThread和VMThread之間同步使用,相當於一個鎖,synchronize方法相當於加鎖方法,未獲取鎖的一方會不斷循環等待,desynchronize方法相當於解鎖方法,會喚醒要想鎖的線程,其實現如下:

void ConcurrentMarkSweepThread::synchronize(bool is_cms_thread) {
  assert(UseConcMarkSweepGC, "just checking");

  MutexLockerEx x(CGC_lock,
                  Mutex::_no_safepoint_check_flag);
  if (!is_cms_thread) {
    //不是CMS Thread就是VMThread
    assert(Thread::current()->is_VM_thread(), "Not a VM thread");
    CMSSynchronousYieldRequest yr;
    //如果CMS_flag是CMS_cms_has_token,即CMS Thread佔用了該鎖,則將其置爲CMS_vm_wants_token,表示VMThread希望佔用該鎖
    //並在CGC_lock上等待
    while (CMS_flag_is_set(CMS_cms_has_token)) {
      //設置CMS_vm_wants_token,此時CMS_cms_has_token還在,這兩個對應不同的位,可以同時存在
      set_CMS_flag(CMS_vm_wants_token);
      CGC_lock->wait(true);
    }
    //退出循環了,CMS_cms_has_token標誌被清除了
    //清除標識
    clear_CMS_flag(CMS_vm_wants_token);
    //設置CMS_vm_has_token,表示當前VMThread佔用了鎖
    set_CMS_flag(CMS_vm_has_token);
  } else {
    //如果是CMS Thread
    assert(Thread::current()->is_ConcurrentGC_thread(),
           "Not a CMS thread");
    //如果標識是CMS_vm_has_token | CMS_vm_wants_token,表示是VMThread佔用了該鎖,在CGC_lock上不斷循環等待
    while (CMS_flag_is_set(CMS_vm_has_token | CMS_vm_wants_token)) {
      //設置CMS_cms_wants_token
      set_CMS_flag(CMS_cms_wants_token);
      CGC_lock->wait(true);
    }
    //退出循環了,說明VMThread釋放了該鎖,CMS_vm_has_token | CMS_vm_wants_token標識被清除了
    //清除標識CMS_cms_wants_token
    clear_CMS_flag(CMS_cms_wants_token);
    //設置標識CMS_cms_has_token
    set_CMS_flag(CMS_cms_has_token);
  }
}

void ConcurrentMarkSweepThread::desynchronize(bool is_cms_thread) {
  assert(UseConcMarkSweepGC, "just checking");

  MutexLockerEx x(CGC_lock,
                  Mutex::_no_safepoint_check_flag);
  if (!is_cms_thread) {
    //不是CMS Thread就是VMThread
    assert(Thread::current()->is_VM_thread(), "Not a VM thread");
    assert(CMS_flag_is_set(CMS_vm_has_token), "just checking");
    //清除標識CMS_vm_has_token,即釋放鎖
    clear_CMS_flag(CMS_vm_has_token);
    if (CMS_flag_is_set(CMS_cms_wants_token)) {
      //如果CMS Thread想要該鎖,則喚醒在CGC_lock上等待的CMS Thread
      CGC_lock->notify();
    }
    assert(!CMS_flag_is_set(CMS_vm_has_token | CMS_vm_wants_token),
           "Should have been cleared");
  } else {
    //如果是CMS Thread
    assert(Thread::current()->is_ConcurrentGC_thread(),
           "Not a CMS thread");
    assert(CMS_flag_is_set(CMS_cms_has_token), "just checking");
    //清除標識CMS_cms_has_token,即釋放鎖
    clear_CMS_flag(CMS_cms_has_token);
    if (CMS_flag_is_set(CMS_vm_wants_token)) {
      //如果VMThread想要鎖,則喚醒在CGC_lock上等待的VMThread
      CGC_lock->notify();
    }
    assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token),
           "Should have been cleared");
  }
}

static bool CMS_flag_is_set(int b)        { return (_CMS_flag & b) != 0;   }

static bool clear_CMS_flag(int b)         { return (_CMS_flag &= ~b) != 0; }

兩方法的調用鏈如下:

 

以SweepClosure::do_yield_work中的調用來說明yeild動作的執行,如下:

void SweepClosure::do_yield_work(HeapWord* addr) {
  
  if (inFreeRange()) {
    flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger()));
  }

  assert_lock_strong(_bitMap->lock());
  assert_lock_strong(_freelistLock);
  assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
         "CMS thread should hold CMS token");
  //釋放鎖
  _bitMap->lock()->unlock();
  _freelistLock->unlock();
  //釋放CMS Token鎖
  ConcurrentMarkSweepThread::desynchronize(true);
  //如果是iCMS模式,則將計數器置0
  ConcurrentMarkSweepThread::acknowledge_yield_request();
  //停止計時器
  _collector->stopTimer();
  GCPauseTimer p(_collector->size_policy()->concurrent_timer_ptr());
  if (PrintCMSStatistics != 0) {
    _collector->incrementYields();
  }
  //如果是iCMS模式,此處會等待直到start_icms方法調用,否則啥都不做
  _collector->icms_wait();

  //如果不是iCMS模式,此時should_yield方法返回true,通過os::sleep讓出CPU使用權限
  //不斷循環直到should_yield方法返回false
  //如果是iCMS模式且stop_icms被再次調用,則should_yield返回true,同樣通過os::sleep讓出CPU使用權限
  //然後執行acknowledge_yield_request,將計數器置0,
  for (unsigned i = 0; i < CMSYieldSleepCount &&
                       ConcurrentMarkSweepThread::should_yield() &&
                       !CMSCollector::foregroundGCIsActive(); ++i) {
    os::sleep(Thread::current(), 1, false);
    ConcurrentMarkSweepThread::acknowledge_yield_request();
  }
  
  //退出循環,CMS Thread重新開始執行,獲取CMS Token鎖
  ConcurrentMarkSweepThread::synchronize(true);
  //重新獲取鎖
  _freelistLock->lock();
  _bitMap->lock()->lock_without_safepoint_check();
  //重啓計時器
  _collector->startTimer();
}

7、CMSTokenSync / CMSTokenSyncWithLocks

     這兩類的定義在同目錄的concurrentMarkSweepGeneration.hpp中,通過構造函數和析構函數來簡化synchronize / desynchronize方法對的調用,CMSTokenSyncWithLocks繼承自CMSTokenSync,其實現如下:

class CMSTokenSync: public StackObj {
 private:
  bool _is_cms_thread;
 public:
  CMSTokenSync(bool is_cms_thread):
    _is_cms_thread(is_cms_thread) {
    assert(is_cms_thread == Thread::current()->is_ConcurrentGC_thread(),
           "Incorrect argument to constructor");
    ConcurrentMarkSweepThread::synchronize(_is_cms_thread);
  }

  ~CMSTokenSync() {
    assert(_is_cms_thread ?
             ConcurrentMarkSweepThread::cms_thread_has_cms_token() :
             ConcurrentMarkSweepThread::vm_thread_has_cms_token(),
          "Incorrect state");
    ConcurrentMarkSweepThread::desynchronize(_is_cms_thread);
  }
};

  static bool cms_thread_has_cms_token() {
    return CMS_flag_is_set(CMS_cms_has_token);
  }
  static bool vm_thread_wants_cms_token() {
    return CMS_flag_is_set(CMS_vm_wants_token);
  }

class CMSTokenSyncWithLocks: public CMSTokenSync {
 private:
  MutexLockerEx _locker1, _locker2, _locker3;
 public:
  CMSTokenSyncWithLocks(bool is_cms_thread, Mutex* mutex1,
                        Mutex* mutex2 = NULL, Mutex* mutex3 = NULL):
    CMSTokenSync(is_cms_thread),
    _locker1(mutex1, Mutex::_no_safepoint_check_flag),
    _locker2(mutex2, Mutex::_no_safepoint_check_flag),
    _locker3(mutex3, Mutex::_no_safepoint_check_flag)
  { }
};

兩者構造方法的調用鏈如下:

 

8、stop / threads_do

      stop方法用於終止當前CMS Thread,將_should_terminate屬性置爲true並等待CMS Thread從run方法中退出;threads_do方法用於處理當前CMS Thread及GC線程池中的線程,其實現如下:

void ConcurrentMarkSweepThread::stop() {
  if (CMSIncrementalMode) {
    //禁止icms模式
    disable_icms();
    //喚醒ICMS_Lock等待的線程
    start_icms();
  }
  {
    MutexLockerEx x(Terminator_lock);
    //_should_terminate置爲true
    _should_terminate = true;
  }
  { //喚醒所有在CGC_lock中等待的線程
    MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
    CGC_lock->notify_all();
  }
  { //獲取鎖Terminator_lock,等待CMS Thread從run方法中退出,退出時會將cmst屬性置爲null
    //並喚醒在Terminator_lock上等待的線程
    MutexLockerEx x(Terminator_lock);
    while(cmst() != NULL) {
      Terminator_lock->wait();
    }
  }
}

void ConcurrentMarkSweepThread::threads_do(ThreadClosure* tc) {
  assert(tc != NULL, "Null ThreadClosure");
  if (_cmst != NULL) {
    //處理相當線程
    tc->do_thread(_cmst);
  }
  assert(Universe::is_fully_initialized(),
         "Called too early, make sure heap is fully initialized");
  if (_collector != NULL) {
    AbstractWorkGang* gang = _collector->conc_workers();
    if (gang != NULL) {
      //處理GC線程池中的線程
      gang->threads_do(tc);
    }
  }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章