Hotspot源码解析-第十二章-JavaThread的创建

2024-01-03 19:52:13

在本章中会大量用到Handle,也就是句柄的概念,那么首先先把指针、引用、句柄的概念搞清楚

1、指针:在C/C++中大量使用指针,表示某个对象/内存的地址,不受 指向的类型限制,只是表示地址,这个概念好理解

2、引用:引用在面向对象语言(C++、Java)中大量存在,可以把引用等价于指针,区别在于,引用限定了类型,声明时是什么类型,就是什么类型,这样的好处就是不至于在运行时产生类型转换的错误

3、句柄:句柄其实就是对指针的一层包装,想像成家里电视机的遥控器,可以遥控很多电视机,句柄就是通过间接访问内存的方式,应对指针在运行过程中发生的变化,比如电视机换了一台,但是遥控还可以控制,就是这个道理

12.1 JavaThread的创建

12.1.1 thread.cpp

12.1.1.1 create_vm

create_vm函数内容太多,这里只截取了与本章相关的内容

// 绑定主线程到os级线程,在`第十一章`中讲过,JavaThread是继承自Thread,注意,这里的JavaThread只是虚拟机层面的Java级线程,并不是我们Java编码层面的线程,这个概念要区分来,但是Java编码层面的线程Thread,最终在虚拟机底层就是用JavaThread来表示的,从这点看,两者又是一样,抛开编码层面,就可以总结为:JavaThread就是一个Java线程的表示,后续章节也会细讲。new JavaThread()的实现细节看`章节12.1.2.1`
  JavaThread* main_thread = new JavaThread();
  // 设置线程状态,thread_state状态跟Java层面线程的状态(new、running等)不是一个概念,这个值主要标注线程当前运行状况,或者说在哪个层面运行,比如Java层面、虚拟机层面、native层面
  main_thread->set_thread_state(_thread_in_vm); 
  // 设置线程栈基址和栈占用空间大小(可以得出栈顶最大值)
  main_thread->record_stack_base_and_size();
  main_thread->initialize_thread_local_storage(); // 初始化线程本地存储
  // 分配JNI句柄存储块,并设置关联到当前线程
  main_thread->set_active_handles(JNIHandleBlock::allocate_block());
  // 将当前线程绑定到OS线程,细节看`章节12.2`
  if (!main_thread->set_as_starting_thread()) {
    // 主线程绑定失败,虚拟机退出
    vm_shutdown_during_initialization(
      "Failed necessary internal allocation. Out of swap space");
    delete main_thread;
    *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
    return JNI_ENOMEM;
  }

  // 创建线程栈保护区,细节看`章节12.3`
  main_thread->create_stack_guard_pages();

12.1.1.2 Thread::allocate

这个函数就是给线程分配内存的,分为两部分,一个是支持偏向锁;一个是不支持偏向锁

void* Thread::allocate(size_t size, bool throw_excpt, MEMFLAGS flags) {
  if (UseBiasedLocking) { // 支持偏向锁
    const int alignment = markOopDesc::biased_lock_alignment;  // 偏向锁对齐大小
    size_t aligned_size = size + (alignment - sizeof(intptr_t)); // 要分配的内存大小
    // 实际分配内存操作,并返回分配的内存首地址
    void* real_malloc_addr = throw_excpt? AllocateHeap(aligned_size, flags, CURRENT_PC)
                                          : AllocateHeap(aligned_size, flags, CURRENT_PC,
                                              AllocFailStrategy::RETURN_NULL);
    // 处理对齐操作
    void* aligned_addr     = (void*) align_size_up((intptr_t) real_malloc_addr, alignment);
    assert(((uintptr_t) aligned_addr + (uintptr_t) size) <=
           ((uintptr_t) real_malloc_addr + (uintptr_t) aligned_size),
           "JavaThread alignment code overflowed allocated storage");
    if (TraceBiasedLocking) {   // 打印日志
      if (aligned_addr != real_malloc_addr)
        tty->print_cr("Aligned thread " INTPTR_FORMAT " to " INTPTR_FORMAT,
                      real_malloc_addr, aligned_addr);
    }
    // 给Thread对象中属性 _real_malloc_address 赋值为分配的内存首地址 
    ((Thread*) aligned_addr)->_real_malloc_address = real_malloc_addr;
    return aligned_addr;
  } else { // 不支持偏向锁,直接分配
    // 用AllocateHeap来在C堆(注意,这里不是Java堆,这个C堆就是所谓的进程运行时堆,参见`章节11.1.1`)中分配内存,AllocateHeap的细节看后面描述
    return throw_excpt? AllocateHeap(size, flags, CURRENT_PC)
                       : AllocateHeap(size, flags, CURRENT_PC, AllocFailStrategy::RETURN_NULL);
  }
}

AllocateHeap函数

inline char* AllocateHeap(size_t size, MEMFLAGS flags,
    AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
  return AllocateHeap(size, flags, CURRENT_PC, alloc_failmode);
}

inline char* AllocateHeap(size_t size, MEMFLAGS flags,
    const NativeCallStack& stack,
    AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
  // 最终分配是通过系统调用malloc来完成的
  char* p = (char*) os::malloc(size, flags, stack);
  #ifdef ASSERT
  if (PrintMallocFree) trace_heap_malloc(size, "AllocateHeap", p);
  #endif
  if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) {
    vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "AllocateHeap");
  }
  return p;
}
12.1.1.3 JavaThread::JavaThread()构造函数
JavaThread::JavaThread(bool is_attaching_via_jni) :
  Thread()  // 先调用父类Thread的构造函数,看`章节12.1.1.4`
#if INCLUDE_ALL_GCS
  , _satb_mark_queue(&_satb_mark_queue_set),
  _dirty_card_queue(&_dirty_card_queue_set)
#endif // INCLUDE_ALL_GCS
{
  // 进一步从Java线程角度初始化,看`章节12.1.1.5`
  initialize();
  if (is_attaching_via_jni) {
    _jni_attach_state = _attaching_via_jni;
  } else {
    _jni_attach_state = _not_attaching_via_jni;
  }
  assert(deferred_card_mark().is_empty(), "Default MemRegion ctor");
}
12.1.1.4 Thread()构造函数
Thread::Thread() {
  // 栈设置
  set_stack_base(NULL); // 设置栈基址为Null
  set_stack_size(0); // 初始化栈大小为0
  set_self_raw_id(0); // 初始化线程原生id
  set_lgrp_id(-1);

  // 数据结构分配
  set_osthread(NULL); // 对应的os线程,初始化时,还没有绑定,所以先设置null
  // 设置资源分配区域,ResourceArea就是管理当前线程分配的内存区域,比如在哪个Chunk块
  set_resource_area(new (mtThread)ResourceArea());
  DEBUG_ONLY(_current_resource_mark = NULL;) // 赋值
  // 设置句柄分配区域,HandleArea就是管理当前线程分配的句柄内存区域,比如在哪个Chunk块、句柄区域链表
  set_handle_area(new (mtThread) HandleArea(NULL));
  // 在C堆中分配最大元素Metadata个数为30的可增长的数组内存,用于存放元数据,并用元数组句柄指向
  set_metadata_handles(new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(30, true));
  // 下面这些属性的含义可以看`章节111.1.4`
  set_active_handles(NULL); // 设置指向当前线程持有的JNI句柄链表头指针,默认为Null
  set_free_handle_block(NULL); // 设置空闲JNI句柄块的链表头指针,默认为Null
  set_last_handle_mark(NULL); // 设置HandleMark的指针,默认为Null

  // This initial value ==> never claimed.
  _oops_do_parity = 0;

  _metadata_on_stack_buffer = NULL;

  // 将当前对象用HandleMark句柄来管理,在句柄链中,初始化时this即是链表头也是链表尾(last_handle_mark)
  new HandleMark(this);

  // 下面就是常规的初始化
  debug_only(_owned_locks = NULL;)
  debug_only(_allow_allocation_count = 0;)
  NOT_PRODUCT(_allow_safepoint_count = 0;)
  NOT_PRODUCT(_skip_gcalot = false;)
  _jvmti_env_iteration_count = 0;
  set_allocated_bytes(0);
  _vm_operation_started_count = 0;
  _vm_operation_completed_count = 0;
  _current_pending_monitor = NULL;
  _current_pending_monitor_is_from_java = true;
  _current_waiting_monitor = NULL;
  _num_nested_signal = 0;
  omFreeList = NULL ;
  omFreeCount = 0 ;
  omFreeProvision = 32 ;
  omInUseList = NULL ;
  omInUseCount = 0 ;

#ifdef ASSERT
  _visited_for_critical_count = false;
#endif

  _SR_lock = new Monitor(Mutex::suspend_resume, "SR_lock", true);
  _suspend_flags = 0;

  // thread-specific hashCode stream generator state - Marsaglia shift-xor form
  _hashStateX = os::random() ;
  _hashStateY = 842502087 ;
  _hashStateZ = 0x8767 ;    // (int)(3579807591LL & 0xffff) ;
  _hashStateW = 273326509 ;

  _OnTrap   = 0 ;
  _schedctl = NULL ;
  _Stalled  = 0 ;
  _TypeTag  = 0x2BAD ;

  // 为各事件分配内存
  _ParkEvent   = ParkEvent::Allocate (this) ;
  _SleepEvent  = ParkEvent::Allocate (this) ;
  _MutexEvent  = ParkEvent::Allocate (this) ;
  _MuxEvent    = ParkEvent::Allocate (this) ;

#ifdef CHECK_UNHANDLED_OOPS
  if (CheckUnhandledOops) {
    _unhandled_oops = new UnhandledOops(this);
  }
#endif // CHECK_UNHANDLED_OOPS
#ifdef ASSERT
  if (UseBiasedLocking) {
    assert((((uintptr_t) this) & (markOopDesc::biased_lock_alignment - 1)) == 0, "forced alignment of thread object failed");
    assert(this == _real_malloc_address ||
           this == (void*) align_size_up((intptr_t) _real_malloc_address, markOopDesc::biased_lock_alignment),
           "bug in forced alignment of thread objects");
  }
#endif /* ASSERT */
}
12.1.1.5 JavaThread::initialize
// A JavaThread is a normal Java thread

void JavaThread::initialize() {
  // Initialize fields

  // Set the claimed par_id to UINT_MAX (ie not claiming any par_ids)
  // 将par_id设置为uint(无符号Int)表示的最大值
  set_claimed_par_id(UINT_MAX);

  set_saved_exception_pc(NULL);
  set_threadObj(NULL);
  _anchor.clear();
  set_entry_point(NULL);
  // 设置jni要用的函数数组jni_NativeInterface,这个数组在jni.cpp文件中定义
  set_jni_functions(jni_functions());
  set_callee_target(NULL);
  set_vm_result(NULL);
  set_vm_result_2(NULL);
  set_vframe_array_head(NULL);
  set_vframe_array_last(NULL);
  set_deferred_locals(NULL);
  set_deopt_mark(NULL);
  set_deopt_nmethod(NULL);
  clear_must_deopt_id();
  set_monitor_chunks(NULL);
  set_next(NULL);
  // 设置线程的状态为new,也就是刚创建
  set_thread_state(_thread_new);
  _terminated = _not_terminated;
  _privileged_stack_top = NULL;
  _array_for_gc = NULL;
  _suspend_equivalent = false;
  _in_deopt_handler = 0;
  _doing_unsafe_access = false;
  _stack_guard_state = stack_guard_unused;
  (void)const_cast<oop&>(_exception_oop = oop(NULL));
  _exception_pc  = 0;
  _exception_handler_pc = 0;
  _is_method_handle_return = 0;
  _jvmti_thread_state= NULL;
  _should_post_on_exceptions_flag = JNI_FALSE;
  _jvmti_get_loaded_classes_closure = NULL;
  _interp_only_mode    = 0;
  _special_runtime_exit_condition = _no_async_condition;
  _pending_async_exception = NULL;
  _thread_stat = NULL;
  _thread_stat = new ThreadStatistics();
  _blocked_on_compilation = false;
  _jni_active_critical = 0;
  _pending_jni_exception_check_fn = NULL;
  _do_not_unlock_if_synchronized = false;
  _cached_monitor_info = NULL;
  _parker = Parker::Allocate(this) ;

#ifndef PRODUCT
  _jmp_ring_index = 0;
  for (int ji = 0 ; ji < jump_ring_buffer_size ; ji++ ) {
    record_jump(NULL, NULL, NULL, 0);
  }
#endif /* PRODUCT */

  set_thread_profiler(NULL);
  if (FlatProfiler::is_active()) {
    // This is where we would decide to either give each thread it's own profiler
    // or use one global one from FlatProfiler,
    // or up to some count of the number of profiled threads, etc.
    ThreadProfiler* pp = new ThreadProfiler();
    pp->engage();
    set_thread_profiler(pp);
  }

  // 设置线程安全点状态信息,底层线程的很多操作都要检查安全点,后面讲GC的时候会讲到
  ThreadSafepointState::create(this);

  debug_only(_java_call_counter = 0);

  // JVMTI PopFrame support
  _popframe_condition = popframe_inactive;
  _popframe_preserved_args = NULL;
  _popframe_preserved_args_size = 0;
  _frames_to_pop_failed_realloc = 0;

  pd_initialize();
}

12.1.2 thread.hpp

12.1.2.1 new JavaThread()

之前在线程描述的第十一章讲过,JavaThread是继承自Thread的,在JavaThread类中没有找到new运算符的实现函数,这种情况一般就要往上找,找它的父类,直到找到为此,很幸运在Thread类中有对new运算符的实现函数

void* operator new(size_t size) throw() { return allocate(size, true); }

在new函数中,实际调用的是allocate函数,该函数在thread.cpp源文件中实现,作用就是在进程的运行时堆中分配一块内存来存放JavaThread对象,分配细节看章节12.1.1.2,内存分配完后,要对JavaThread对象做一些赋值和初始化的工作,初始化细节看章节12.1.1.3

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