目錄
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);
}
}
}