1. VMThread::inner_execute() - 觸發安全點??
cpp
復制
void VMThread::inner_execute(VM_Operation* op) { if (op->evaluate_at_safepoint()) { SafepointSynchronize::begin(); // 進入安全點,阻塞所有線程 // ...執行GC等操作... SafepointSynchronize::end(); // 結束安全點,喚醒線程 } }
- ??功能??:執行需要安全點的 VM 操作(如 GC)。
- ??關鍵點??:
SafepointSynchronize::begin()
:暫停所有線程,進入安全點。SafepointSynchronize::end()
:完成 GC 后,調用此函數解除線程阻塞。
??2. SafepointSynchronize::end() - 結束安全點??
cpp
復制
void SafepointSynchronize::end() { disarm_safepoint(); // 核心:解除安全點 Universe::heap()->safepoint_synchronize_end(); // GC后清理 }
- ??功能??:安全點結束時的清理工作。
- ??核心調用??:
disarm_safepoint()
?負責恢復線程運行。
??3. SafepointSynchronize::disarm_safepoint() - 解除安全點??
cpp
復制
void SafepointSynchronize::disarm_safepoint() { _state = _not_synchronized; // 全局狀態標記為非同步 Atomic::store(&_safepoint_counter, _safepoint_counter + 1); // 遞增安全點ID // 恢復所有線程狀態 for (JavaThread *current : JavaThreadIterator()) { current->safepoint_state()->restart(); // 標記線程為運行狀態 } _wait_barrier->disarm(); // 喚醒阻塞的線程 Threads_lock->unlock(); // 解鎖線程列表 }
- ??功能??:
- 將全局安全點狀態設置為 ??非同步??。
- 更新安全點計數器,觸發內存屏障保證可見性。
- 遍歷所有線程,調用?
restart()
?重置線程狀態。 - 調用屏障的?
disarm()
?方法喚醒所有線程。
??4. LinuxWaitBarrier::disarm() - 喚醒線程??
cpp
復制
void LinuxWaitBarrier::disarm() { _futex_barrier = 0; // 重置屏障值 syscall(SYS_futex, &_futex_barrier, FUTEX_WAKE_PRIVATE, INT_MAX); // 喚醒所有等待線程 }
- ??功能??:通過 Linux 的?
futex
?系統調用喚醒所有阻塞在安全點的線程。 - ??關鍵點??:
FUTEX_WAKE_PRIVATE
:喚醒所有在?_futex_barrier
?上等待的線程。INT_MAX
:喚醒最大數量的線程(實際喚醒所有等待的線程)。
??5. 線程阻塞與喚醒機制??
- ??線程阻塞??:
- 在安全點開始時,線程通過?
SafepointSynchronize::block()
?調用?futex
?的?FUTEX_WAIT
?進入阻塞狀態。
cpp
復制
void SafepointSynchronize::block(JavaThread* thread) { _wait_barrier->wait(active_safepoint_id); // FUTEX_WAIT }
- 在安全點開始時,線程通過?
- ??線程喚醒??:
- GC 完成后,
disarm_safepoint()
?調用?LinuxWaitBarrier::disarm()
,通過?FUTEX_WAKE
?喚醒所有阻塞線程。
- GC 完成后,
??總結??
- ??安全點進入??:GC 開始時,所有線程通過?
futex
?進入阻塞狀態。 - ??GC 執行??:VM 線程在安全點內執行垃圾回收。
- ??安全點退出??:
- 更新全局狀態和計數器。
- 重置每個線程的運行狀態。
- 調用?
futex
?的?FUTEX_WAKE
?喚醒所有線程。
- ??線程恢復??:被喚醒的線程繼續執行后續代碼。
這些代碼是 ??垃圾回收完成后解除線程阻塞的核心實現??,通過操作系統提供的?futex
?機制高效地管理線程的阻塞與喚醒。
?##源碼
void VMThread::inner_execute(VM_Operation* op) {assert(Thread::current()->is_VM_thread(), "Must be the VM thread");VM_Operation* prev_vm_operation = NULL;if (_cur_vm_operation != NULL) {// Check that the VM operation allows nested VM operation.// This is normally not the case, e.g., the compiler// does not allow nested scavenges or compiles.if (!_cur_vm_operation->allow_nested_vm_operations()) {fatal("Unexpected nested VM operation %s requested by operation %s",op->name(), _cur_vm_operation->name());}op->set_calling_thread(_cur_vm_operation->calling_thread());prev_vm_operation = _cur_vm_operation;}_cur_vm_operation = op;HandleMark hm(VMThread::vm_thread());EventMarkVMOperation em("Executing %sVM operation: %s", prev_vm_operation != NULL ? "nested " : "", op->name());log_debug(vmthread)("Evaluating %s %s VM operation: %s",prev_vm_operation != NULL ? "nested" : "",_cur_vm_operation->evaluate_at_safepoint() ? "safepoint" : "non-safepoint",_cur_vm_operation->name());bool end_safepoint = false;if (_cur_vm_operation->evaluate_at_safepoint() &&!SafepointSynchronize::is_at_safepoint()) {SafepointSynchronize::begin();if (_timeout_task != NULL) {_timeout_task->arm();}end_safepoint = true;}evaluate_operation(_cur_vm_operation);if (end_safepoint) {if (_timeout_task != NULL) {_timeout_task->disarm();}SafepointSynchronize::end();}_cur_vm_operation = prev_vm_operation;
}// Wake up all threads, so they are ready to resume execution after the safepoint
// operation has been carried out
void SafepointSynchronize::end() {assert(Threads_lock->owned_by_self(), "must hold Threads_lock");EventSafepointEnd event;assert(Thread::current()->is_VM_thread(), "Only VM thread can execute a safepoint");disarm_safepoint();Universe::heap()->safepoint_synchronize_end();SafepointTracing::end();post_safepoint_end_event(event, safepoint_id());
}void SafepointSynchronize::disarm_safepoint() {uint64_t active_safepoint_counter = _safepoint_counter;{JavaThreadIteratorWithHandle jtiwh;
#ifdef ASSERT// A pending_exception cannot be installed during a safepoint. The threads// may install an async exception after they come back from a safepoint into// pending_exception after they unblock. But that should happen later.for (; JavaThread *cur = jtiwh.next(); ) {assert (!(cur->has_pending_exception() &&cur->safepoint_state()->is_at_poll_safepoint()),"safepoint installed a pending exception");}
#endif // ASSERTOrderAccess::fence(); // keep read and write of _state from floating upassert(_state == _synchronized, "must be synchronized before ending safepoint synchronization");// Change state first to _not_synchronized.// No threads should see _synchronized when running._state = _not_synchronized;// Set the next dormant (even) safepoint id.assert((_safepoint_counter & 0x1) == 1, "must be odd");Atomic::release_store(&_safepoint_counter, _safepoint_counter + 1);OrderAccess::fence(); // Keep the local state from floating up.jtiwh.rewind();for (; JavaThread *current = jtiwh.next(); ) {// Clear the visited flag to ensure that the critical counts are collected properly.DEBUG_ONLY(current->reset_visited_for_critical_count(active_safepoint_counter);)ThreadSafepointState* cur_state = current->safepoint_state();assert(!cur_state->is_running(), "Thread not suspended at safepoint");cur_state->restart(); // TSS _runningassert(cur_state->is_running(), "safepoint state has not been reset");}} // ~JavaThreadIteratorWithHandle// Release threads lock, so threads can be created/destroyed again.Threads_lock->unlock();// Wake threads after local state is correctly set._wait_barrier->disarm();
}// Guarantees any thread that called wait() will be awake when it returns.// Provides a trailing fence.void disarm() {assert(_owner == Thread::current(), "Not owner thread");_impl.disarm();}// Guarantees any thread that called wait() will be awake when it returns.// Provides a trailing fence.void disarm() {assert(_owner == Thread::current(), "Not owner thread");_impl.disarm();}void LinuxWaitBarrier::disarm() {assert(_futex_barrier != 0, "Should be armed/non-zero.");_futex_barrier = 0;int s = futex(&_futex_barrier,FUTEX_WAKE_PRIVATE,INT_MAX /* wake a max of this many threads */);guarantee_with_errno(s > -1, "futex FUTEX_WAKE failed");
}static int futex(volatile int *addr, int futex_op, int op_arg) {return syscall(SYS_futex, addr, futex_op, op_arg, NULL, NULL, 0);
}