本文主要是介绍Hotspot源码解析-第十二章-JavaThread的创建,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
在本章中会大量用到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 againreturn 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 ASSERTif (PrintMallocFree) trace_heap_malloc(size, "AllocateHeap", p);#endifif (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); // 设置栈基址为Nullset_stack_size(0); // 初始化栈大小为0set_self_raw_id(0); // 初始化线程原生idset_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句柄链表头指针,默认为Nullset_free_handle_block(NULL); // 设置空闲JNI句柄块的链表头指针,默认为Nullset_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_OOPSif (CheckUnhandledOops) {_unhandled_oops = new UnhandledOops(this);}
#endif // CHECK_UNHANDLED_OOPS
#ifdef ASSERTif (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 threadvoid 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
这篇关于Hotspot源码解析-第十二章-JavaThread的创建的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!