目录
4、CMSSynchronousYieldRequest / asynchronous_yield_request / acknowledge_yield_request / should_yield
5、stop_icms / icms_wait / start_icms
7、CMSTokenSync / CMSTokenSyncWithLocks
本篇博客讲解在后台执行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);
}
}
}