在本章中会大量用到Handle,也就是句柄的概念,那么首先先把指针、引用、句柄的概念搞清楚
1、指针:在C/C++中大量使用指针,表示某个对象/内存的地址,不受 指向的类型限制,只是表示地址,这个概念好理解
2、引用:引用在面向对象语言(C++、Java)中大量存在,可以把引用等价于指针,区别在于,引用限定了类型,声明时是什么类型,就是什么类型,这样的好处就是不至于在运行时产生类型转换的错误
3、句柄:句柄其实就是对指针的一层包装,想像成家里电视机的遥控器,可以遥控很多电视机,句柄就是通过间接访问内存的方式,应对指针在运行过程中发生的变化,比如电视机换了一台,但是遥控还可以控制,就是这个道理
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();
这个函数就是给线程分配内存的,分为两部分,一个是支持偏向锁;一个是不支持偏向锁
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;
}
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");
}
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(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 */
}
// 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(_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();
}
之前在线程描述的第十一章讲过,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