Hotspot源码解析-第24章-创建虚拟机线程

发布时间:2024年01月24日

第24章-创建虚拟机线程

虚拟机线程在虚拟中通过类 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);
}

24.1 创建并关联操作系统线程

24.1.1 os_linux.cpp

24.1.1.1 os::create_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;
}
24.1.1.2 os::pd_start_thread
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
}

文章来源:https://blog.csdn.net/zhang527294844/article/details/135828253
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。