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

2024-01-04 06:28

本文主要是介绍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的创建的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/568426

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听