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);
    }
  }
}
发布了117 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_31865983/article/details/104114865