jvm15版本源码阅读之宏开始初始化到init_globals之前


  上一篇分析了在HOTSPOT_VM_INIT_BEGIN之前的初始化部分,这里开始从此宏之后的初始化部分.此部分内容会很多,涉及多个java的核心概念.

1 宏之后到init_globals之前的初始化方法

1.1 SafepointMechanism::initialize

  这是安全点的初始化,主要和gc有关,具体和oopMap紧密相连.初始化的主要目的是设置Polling page,此类内存页也是诱使线程进入安全点的手段之一,如下所示
在这里插入图片描述
  可见,设置了一个是系统默认页大小两倍的polling page,并设置为保护模式下的不可读属性,因此当有线程来访问此页时会报错,这个报错信号被jvm捕获后就可以阻塞线程,使其进入安全点的范畴.
  Java的安全点和安全区机制是一个核心机制,之后会安排单独解析.

1.2 ostream_init_log

  这个是在ostream_init之后进行的,是初始化输出流的log格式等.

1.3 Arguments::init_libraries_at_startup

  为了能把-Xrun参数值转换成agentlib的库文件,这个初始化方法是判断agentlib文件列表是否为空.

1.4 Arguments::init_agents_at_startup

  同上面的一样,这里是判断agent的列表是否为空,也是为了转换-Xrun的参数.

1.5 vm_init_globals

  这个方法是初始化一些全局的数据结构和加载系统类.
在这里插入图片描述
  1 threadshadow初始化,该类是处理线程的exception,是所有线程类的父类.线程的exception是从外部挂上去的,这个挂载就是threadshadow类,所以就像是影子一样如影随从.
  2 basic_types初始化,基本类型的初始化,判断类型和大小是否是正确
  3 eventlog的初始化,全部事件有消息,违例,多重定义,类未加载和破环优化的消息.
  4 互斥锁初始化,使用宏定义来预先定义了所有的互斥锁类型
  5 oop存储初始化,如下所示在这里插入图片描述
  共有6种类型的存储,jni全局引用,vm全局引用,jni弱引用,vm弱引用,字符串表的弱引用以及解析方法表弱引用.
  6 小块内存初始化
  7 永久区内存初始化
  8 挂起的线程初始化

1.6 JavaThread* main_thread = new JavaThread()

  创建java线程.jvm中只有两种线程,一种是JavaThread,另一种是NonJavaThread.
  其构造方法如下:
在这里插入图片描述

  首先,其继承自Thread类,进入该类,可见
在这里插入图片描述
  其关联了一个os的thread,也就是系统的thread,在unix系统上就是posix的thread库,该库调用了系统调用来创建线程,所以JavaThread是内核线程的描述操作类,本质上是内核线程.
  再回到下面的initialize方法,进入该方法,可见
在这里插入图片描述

  这里只是截取了一部分代码,但是重要的初始化设置是ThreadSafepointState和SafepointMechanism的设置,可见每个java线程都支持安全点.

1.7 main_thread->set_thread_state

  设置线程状态,这里为_thread_in_vm,即vm内运行线程

1.8 main_thread->initialize_thread_current

  初始化当前线程,此处的当前是针对全局来说的,因为该方法调用了ThreadLocalStorage类,而该类每次只能存一个线程的key和指针.
在这里插入图片描述

  首先判断ThreadLocalStorage存储的线程为空,然后设置了这个唯一的线程为main_thread.

1.9 main_thread->record_stack_base_and_size

  记录该栈的栈顶和大小,进入此方法
在这里插入图片描述

  主要就是获取栈顶,进入os::current_stack_base方法
在这里插入图片描述

  核心方法current_stack_region,进入此方法,首先看到的是注释,如下
在这里插入图片描述
  Java的线程栈布局分为三部分,从上往下看,第一部分是glibc的守护页,此处是修改字节码用的,第二部分是vm的守护内存页,第三部分是正常的栈区.
  在之前的初始化过程中已经最先把guard page的部分先压入栈中了,包括red,yellow和reserve部分的内存页.
  此图的标识比较迷惑,很明显,此处java线程的栈底是P1,但是图中标识为P2.代码中也给出了stack_base是lowaddress加上size的和,所以这里stak_base其实就是栈顶.可见java线程的栈的设计是向下生长的,在计算出当前的栈底之后,在其上(图中所示)加入了glibc区.
  再进入方法内部
在这里插入图片描述

  红框内的三个方法都是系统库的方法,分别是获取当前栈指,栈顶和大小,而目前我们依然还在0号线程内,所以此时获取的都是0号线程内的栈信息.

1.10 main_thread->register_thread_stack_with_NMT

  此方法是在MemTracker类中记载了栈的信息,也就是前面给出的信息.

1.11 main_thread->set_active_handles

  Handles这里只是用来描述线程正在做的事,这里把线程设置为了阻塞.
在这里插入图片描述

1.12 main_thread->set_as_starting_thread

  设置为方法执行线程,进入该方法
在这里插入图片描述

  执行了os::create_main_thread,进入该方法
在这里插入图片描述
  执行了create_attached_thread方法,该方法就是把java线程的描述挂载到os的线程上,进入该方法
在这里插入图片描述

  重要的就是创建了OSThread,也就是os的线程,至此java线程就和os线程对应起来了.

1.13 main_thread->create_stack_guard_pages

  创建守护页,此处守护页仅指glibc部分,根据之前java线程的栈布局,仅在栈底之上加入此部分即可.这里就是用了mprotect方法来在正常的栈之上创建了glibc的守护页.

1.14 ObjectMonitor::Initialize

  这个是和java synchronized的用法相关,是监视区的初始化,使用的都是宏,不难推测最终调用的是系统的mutex互斥锁.

1.15 init_globals

  这个是最核心的初始化部分,涉及的内容有
  1 management_init();
  2 bytecodes_init();
  3 classLoader_init1();
  4 compilationPolicy_init();
  5 codeCache_init();
  6 VM_Version_init();
  7 stubRoutines_init1();
  8 universe_init();
  9 gc_barrier_stubs_init();
  10 interpreter_init_stub();
  11 accessFlags_init();
  12 InterfaceSupport_init();
  13 SharedRuntime::generate_stubs();
  14 universe2_init();
  15 javaClasses_init();
  16 interpreter_init_code();
  17 invocationCounter_init();
  18 referenceProcessor_init();
  19 jni_handles_init();
  20 vmStructs_init();
  21 vtableStubs_init();
  22 InlineCacheBuffer_init();
  23 compilerOracle_init();
  24 dependencyContext_init();
  25 compileBroker_init();
  26 JVMCI::initialize_globals();
  27 universe_post_init();
  28 stubRoutines_init2();
  29 MethodHandles::generate_adapters();
  这部分会在后续章节中分析.

2 小结

  至此,在init_globals之前,main_thread在vm代码层面已经创建了,并且和os的一个线程已经对接上了,但是还没有启动,更重要的是,main_thread所记录的栈区信息依然是0号线程当前的栈区信息,也就是说目前所有的执行还在0号线程内,只是把目前0号线程的栈区布局改为了java的布局,也就是添加了守护页区.
  从宏开始后,这里分析了一些初始化方法,但是还没有进入到最核心的初始化方法中,之后会继续分析这些最核心的初始化部分.同时涉及到了java的安全点及线程模型的一些内容,这些内容打算在分析完全貌后给出一个整理.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值