虚拟机线程在虚拟中通过类 VMThread 来表示,主要的功能就是GC回收,这一章就讲解下它的创建流程和细节。
调用入口还是从 thread.cpp->create_vm()开始
这里摘取 create_vm() 函数的部分代码
{ MutexLocker mu(Threads_lock);
// 这里继续之前主线程的处理,最终要把主线程 main_thread 加入到线程链(表)中
Threads::add(main_thread);
}
// Any JVMTI raw monitors entered in onload will transition into
// real raw monitor. VM is setup enough here for raw monitor enter.
JvmtiExport::transition_pending_onload_raw_monitors();
// Create the VMThread
{ TraceTime timer("Start VMThread", TraceStartupTime);
VMThread::create(); // 创建VMThread 对象
Thread* vmthread = VMThread::vm_thread(); // 拿到上面创建的 VMThread 对象
// 上面只是在语言层面创建了一个“线程”,这一步才是真正去创建一个操作系统级的线程,并与语言层面的线程关联起来,看`章节24.1`
if (!os::create_thread(vmthread, os::vm_thread))
vm_exit_during_initialization("Cannot create VM thread. Out of system resources.");
// vmthread 创建完后,等待运行
{
MutexLocker ml(Notify_lock);
// 启动 vmthread,开始运行,怎么启动呢,实际上就是通知create_thread函数中的 sync_with_child 锁等待
os::start_thread(vmthread);
while (vmthread->active_handles() == NULL) {
Notify_lock->wait();
}
}
}
assert (Universe::is_fully_initialized(), "not initialized");
if (VerifyDuringStartup) { // 默认是 false
// Make sure we're starting with a clean slate.
VM_Verify verify_op;
VMThread::execute(&verify_op); // 执行验证操作
}
创建VMThread对象
void VMThread::create() {
// 判重
assert(vm_thread() == NULL, "we can only allocate one VMThread");
// VMThread 对象创建
_vm_thread = new VMThread();
// 创建虚拟机操作队列,VM 线程执行时就从该队列中取任务执行
_vm_queue = new VMOperationQueue();
guarantee(_vm_queue != NULL, "just checking");
_terminate_lock = new Monitor(Mutex::safepoint, "VMThread::_terminate_lock", true);
if (UsePerfData) { // 有关性能数据
// jvmstat performance counters
Thread* THREAD = Thread::current();
_perf_accumulated_vm_operation_time =
PerfDataManager::create_counter(SUN_THREADS, "vmOperationTime",
PerfData::U_Ticks, CHECK);
}
}
start_thread()启动线程
void os::start_thread(Thread* thread) {
// guard suspend/resume
MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
OSThread* osthread = thread->osthread();
// 这些状态都是 Java/VM 层面对线程的状态描述,操作系统级线程,是没有这些状态的
osthread->set_state(RUNNABLE);
// 看`章节24.1.1.2`
pd_start_thread(thread);
}
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
assert(thread->osthread() == NULL, "caller responsible");
// 创建并分配 OSThread 对象,线程的关系图可以回头去看`章节11.1.3`
OSThread* osthread = new OSThread(NULL, NULL);
if (osthread == NULL) {
return false;
}
// 设置线程类型,一个枚举值,这里是 os::vm_thread
osthread->set_thread_type(thr_type);
// 初始状态 is ALLOCATED 而不是 INITIALIZED
osthread->set_state(ALLOCATED);
// 设置对应的os 线程对象
thread->set_osthread(osthread);
/* 线程属性 POSIX 线程(pthreads)库的一部分
主要作用是将指定的线程置于分离状态(detached state)。一旦线程处于分离状态,它在终止时会自动释放其资源,包括线程的堆栈和线程描述符。这样,其他线程就不需要也无法再对该线程调用 `pthread_join` 来回收其资源。
默认状态下,线程在被创建时默认为可结合的(joinable),意味着它可以被其他线程通过 `pthread_join` 函数等待并回收其资源。
分离状态 的线程则在终止后会自动释放所有资源,无需其他线程参与或干预。
使用 `pthread_detach` 可以避免在不需要等待线程结束或者不打算回收任何资源的情况下,线程因阻塞主线程而导致性能问题。
总结来说,`pthread_detach` 的主要作用是允许开发者在不依赖 `pthread_join` 的情况下,确保线程终止时可以自动释放其所占有的资源,提高程序的效率并减少潜在的内存泄漏问题
*/
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// stack size 线程栈大小处理
if (os::Linux::supports_variable_stack_size()) {
// calculate stack size if it's not specified by caller
if (stack_size == 0) {
// 如果函数中没有传入stack_size 那就是 0,这时就要用默认的栈大小(64位机器是1M,32位是512K,这里只讲32位,所以是512K)
stack_size = os::Linux::default_stack_size(thr_type);
switch (thr_type) {
case os::java_thread:
// Java threads use ThreadStackSize which default value can be
// changed with the flag -Xss
assert (JavaThread::stack_size_at_create() > 0, "this should be set");
stack_size = JavaThread::stack_size_at_create();
break;
case os::compiler_thread:
if (CompilerThreadStackSize > 0) {
stack_size = (size_t)(CompilerThreadStackSize * K);
break;
} // else fall through:
// use VMThreadStackSize if CompilerThreadStackSize is not defined
case os::vm_thread:
case os::pgc_thread:
case os::cgc_thread:
case os::watcher_thread:
// 如果设置了 VMThreadStackSize ,那就用 这个值
if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
break;
}
}
// 栈大小不能小于最小 os::Linux::min_stack_allowed = 64 * K
stack_size = MAX2(stack_size, os::Linux::min_stack_allowed);
// 设置栈空间大小
pthread_attr_setstacksize(&attr, stack_size);
} else {
// let pthread_create() pick the default value.
}
// 线程保护页大小,默认就是一个page size 4 * K
pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));
ThreadState state;
{
// Serialize thread creation if we are running with fixed stack LinuxThreads
bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
if (lock) {
os::Linux::createThread_lock()->lock_without_safepoint_check();
}
pthread_t tid;
// 真正创建线程的函数,创建完后,执行的函数是 java_start 这个函数,具体用的时候再讲
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
// 用完了,销毁 attr 属性对象
pthread_attr_destroy(&attr);
// 创建失败,恢复数据,并销毁 osthread 对象
if (ret != 0) {
if (PrintMiscellaneous && (Verbose || WizardMode)) {
perror("pthread_create()");
}
// Need to clean up stuff we've allocated so far
thread->set_osthread(NULL);
delete osthread;
if (lock) os::Linux::createThread_lock()->unlock();
return false;
}
// 创建成功,就把 pthread 信息存储到 OSThread 对象
osthread->set_pthread_id(tid);
// Wait until child thread is either initialized or aborted
{
Monitor* sync_with_child = osthread->startThread_lock();
MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
while ((state = osthread->get_state()) == ALLOCATED) {
// 如果线程还是 ALLOCATED 状态,就要一直锁等待
sync_with_child->wait(Mutex::_no_safepoint_check_flag);
}
}
if (lock) {
os::Linux::createThread_lock()->unlock();
}
}
// Aborted due to thread limit being reached
if (state == ZOMBIE) {
thread->set_osthread(NULL);
delete osthread;
return false;
}
// 状态验证,线程状态什么时候改变成 INITIALIZED 的,实际上是在 java_start 这个函数中
assert(state == INITIALIZED, "race condition");
return true;
}
void os::pd_start_thread(Thread* thread) {
OSThread * osthread = thread->osthread();
assert(osthread->get_state() != INITIALIZED, "just checking");
Monitor* sync_with_child = osthread->startThread_lock();
MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
sync_with_child->notify(); // 直接看这一行,就是解锁 sync_with_child
}