JVM源码分析之JVM启动流程
原创申明:本文由公众号【猿灯塔】原创,转载请说明出处标注
“365篇原创计划”第十四篇。
今天呢!灯塔君跟大家讲:
JVM源码分析之JVM启动流程
前言:
执行Java类的main方法,程序就能运行起来,main方法的背后,虚拟机究竟发生了什么?如果你对这个感兴趣,相信本文会给你一个答案,本文分析的openjdk版本为openjdk-7-fcs-src-b147-27
class BootStrap {
public static void main(String[] args) {
for (String str : args) {
System.out.println(str);
}
}
} java BootStrap -Xms6G -Xmx8G -Xmn3G -Xss512k
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC
虚拟机的启动入口位于share/tools/launcher/java.c
的main方法,整个流程分为如下几个步骤:
1、配置JVM装载环境
2、解析虚拟机参数
3、设置线程栈大小
4、执行Java main方法
1、配置JVM装载环境
Java代码执行时需要一个JVM环境,JVM环境的创建包括两部分:JVM.dll文件的查找和装载。
JVM.dll文件的查找
通过CreateExecutionEnvironment
方法实现,根据当前JRE环境的路径和系统版本寻找jvm.cfg
文件,windows实现如下:
大概实现逻辑:
1、GetJREPath
查找当前JRE环境的所在路径;
2、ReadKnownVms
读取JRE路径\lib\ARCH(CPU构架)\JVM.cfg
文件,其中ARCH(CPU构架)
通过GetArch
方法获取,在window下有三种情况:amd64、ia64和i386;3、CheckJvmType
确定当前JVM类型,先判断是否通过-J
、-XXaltjvm=
或-J-XXaltjvm=
参数指定,如果没有,则读取JVM.cfg文件中配置的第一个类型;4、GetJVMPath
根据上一步确定的JVM类型,找到对应的JVM.dll文件;
JVM.dll文件的装载
初始化虚拟机中的函数调用,即通过JVM中的方法调用JVM.dll文件中定义的函数,实现如下:
1、LoadLibrary
方法装载JVM.dll动态连接库;2、把JVM.dll文件中定义的函数JNI_CreateJavaVM
和JNI_GetDefaultJavaVMInitArgs
绑定到InvocationFunctions变量的CreateJavaVM
和GetDefaultJavaVMInitArgs
函数指针变量上;
2、虚拟机参数解析
装载完JVM环境之后,需要对启动参数进行解析,其实在装载JVM环境的过程中已经解析了部分参数,该过程通过ParseArguments
方法实现,并调用AddOption
方法将解析完成的参数保存到JavaVMOption
中,JavaVMOption
结构实现如下:
AddOption方法实现如下:
这里对-Xss
参数进行特殊处理,并设置threadStackSize,因为参数格式比较特殊,其它是key/value键值对,它是-Xss512
的格式。后续Arguments
类会对JavaVMOption
数据进行再次处理,并验证参数的合理性。
参数处理
Arguments::parse_each_vm_init_arg
方法负责处理经过解析过的JavaVMOption数据,部分实现如下:
这里只列出三个常用的参数:
1、-Xmn:设置新生代的大小NewSize和MaxNewSize;
2、-Xms:设置堆的初始值InitialHeapSize,也是堆的最小值;
3、-Xmx:设置堆的最大值MaxHeapSize;
参数验证
Arguments::check_gc_consistency
方法负责验证虚拟机启动参数中配置GC的合理性,实现如下:
1、如果参数为-XX:+UseSerialGC -XX:+UseParallelGC
,由于UseSerialGC和UseParallelGC不能兼容,JVM启动时会抛出错误信息;2、如果参数为-XX:+UseConcMarkSweepGC -XX:+UseParNewGC
,其中UseConcMarkSweepGC和UseParNewGC可以兼容,JVM可以正常启动;
3、设置线程栈大小
如果启动参数未设置-Xss
,即threadStackSize为0,则调用InvocationFunctions的GetDefaultJavaVMInitArgs
方法获取JavaVM的初始化参数,即调用JVM.dll函数JNI_GetDefaultJavaVMInitArgs
,定义在share\vm\prims\jni.cpp
,实现如下:
ThreadStackSize
定义在globals.hpp
中,根据当前系统类型,加载对应的配置文件,所以在不同的系统中,ThreadStackSize
的默认值也不同。
4、执行Java main方法
线程栈大小确定后,通过ContinueInNewThread
方法创建新线程,并执行JavaMain函数,JavaMain函数的大概流程如下:
1、新建JVM实例
InitializeJVM
方法调用InvocationFunctions的CreateJavaVM
方法,即调用JVM.dll函数
JNI_CreateJavaVM
,新建一个JVM实例,该过程比较复杂,会在后续文章进行分析;
2、加载主类的class
Java运行方式有两种:jar方式和class方式。
jar方式
1、调用GetMainClassName
方法找到META-INF/MANIFEST.MF
文件指定的Main-Class的主类名;
2、调用LoadClass
方法加载主类的class文件;
class方式
1、调用NewPlatformString
方法创建类名的String对象;
2、调用LoadClass
方法加载主类的class文件;
3、查找main方法
通过GetStaticMethodID
方法查找指定方法名的静态方法,实现如下:
最终调用JVM.dll
函数jni_GetStaticMethodID
实现
其中get_method_id
方法根据类文件对应的instanceKlass对象查找指定方法。
4、执行main方法
1、重新创建参数数组;2、其中mainID是main方法的入口地址,CallStaticVoidMethod
方法最终调用JVM.dll
中的jni_CallStaticVoidMethodV
函数,实现如下
jni_invoke_static实现如下:
最终通过JavaCalls::call
执行main方法。
365天干货不断微信搜索「猿灯塔」第一时间阅读,回复【资料】【面试】【简历】有我准备的一线大厂面试资料和简历模板
JVM源码分析之JVM启动流程的更多相关文章
- Tomcat源码分析之—具体启动流程分析
从Tomcat启动调用栈可知,Bootstrap类的main方法为整个Tomcat的入口,在init初始化Bootstrap类的时候为设置Catalina的工作路径也就是Catalina_HOME信息 ...
- Jvm(jdk8)源码分析1-java命令启动流程详解
JDK8加载源码分析 1.概述 现在大多数互联网公司都是使用java技术体系搭建自己的系统,所以对java开发工程师以及java系统架构师的需求非常的多,虽然普遍的要求都是需要熟悉各种java开发框架 ...
- [Abp vNext 源码分析] - 1. 框架启动流程分析
一.简要说明 本篇文章主要剖析与讲解 Abp vNext 在 Web API 项目下的启动流程,让大家了解整个 Abp vNext 框架是如何运作的.总的来说 ,Abp vNext 比起 ABP 框架 ...
- Tomcat源码分析(从启动流程到请求处理)
Tomcat 8.5下载地址 https://tomcat.apache.org/download-80.cgi Tomcat启动流程 Tomcat源码目录 catalina目录 catalina包含 ...
- Android进阶系列之源码分析Activity的启动流程
美女镇楼,辟邪! 源码,是一个程序猿前进路上一个大的而又不得不去翻越障碍,我讨厌源码,看着一大堆.5000多行,要看完得啥时候去了啊.不过做安卓的总有这一天,自从踏上这条不归路,我就认命了.好吧,我慢 ...
- JVM源码分析-类加载场景实例分析
A类调用B类的静态方法,除了加载B类,但是B类的一个未被调用的方法间接使用到的C类却也被加载了,这个有意思的场景来自一个提问:方法中使用的类型为何在未调用时尝试加载?. 场景如下: public cl ...
- JVM源码分析之堆外内存完全解读
JVM源码分析之堆外内存完全解读 寒泉子 2016-01-15 17:26:16 浏览6837 评论0 阿里技术协会 摘要: 概述 广义的堆外内存 说到堆外内存,那大家肯定想到堆内内存,这也是我们 ...
- JVM源码分析之Metaspace解密
概述 metaspace,顾名思义,元数据空间,专门用来存元数据的,它是jdk8里特有的数据结构用来替代perm,这块空间很有自己的特点,前段时间公司这块的问题太多了,主要是因为升级了中间件所 ...
- JVM源码分析-JVM源码编译与调试
要分析JVM的源码,结合资料直接阅读是一种方式,但是遇到一些想不通的场景,必须要结合调试,查看执行路径以及参数具体的值,才能搞得明白.所以我们先来把JVM的源码进行编译,并能够使用GDB进行调试. 编 ...
随机推荐
- Java中TreeSet的详细用法
第1部分 TreeSet介绍 TreeSet简介 TreeSet 是一个有序的集合,它的作用是提供有序的Set集合.它继承于AbstractSet抽象类,实现了NavigableSet, Clonea ...
- Java实现 洛谷 P1000 超级玛丽游戏
public class Main { public static void main(String[] args){ System.out.println(" ********" ...
- java矩形的关系
在编写图形界面软件的时候,经常会遇到处理两个矩形的关系. 如图[1.jpg]所示,矩形的交集指的是:两个矩形重叠区的矩形,当然也可能不存在(参看[2.jpg]). 两个矩形的并集指的是:能包含这两个矩 ...
- java实现自行车行程
** 自行车行程** 计算行程 低碳生活,有氧运动.骑自行车出行是个好主意.小明为自己的自行车装了个计数器,可以计算出轮子转动的圈数.在一次骑车旅行中,出发时计算器的示数为begin,到达目的地时的示 ...
- java实现第三届蓝桥杯提取子串
提取子串 [代码填空](满分16分) 串"abcba"以字母"c"为中心左右对称:串"abba" 是另一种模式的左右对称.这两种情况我们都称 ...
- cuda 9.0
https://docs.nvidia.com/cuda/archive/9.0/index.html cuda9.0工具包
- k8s+docker部署Golang项目
Go环境搭建 root账户 下载Golang [root@infra2-test-k8s /]# cd /usr/local/ [root@infra2-test-k8s local]# wget h ...
- @Component、@Service、@Controller、@Rrepository说明
自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html 1 Spring容 ...
- Arduino + RFID 读取 IC 卡 Arduino uno中获得RFID的UID 并通过串口转发RFID卡号
RFID简介:射频识别即RFID(Radio Frequency IDentification)技术,又称无线射频识别,是一种通信技术,可通过无线电讯号识别特定目标并读写相关数据,而无需识别系统与特定 ...
- 附015.Kubernetes其他技巧
一 优化镜像源 1.1 国内镜像源 global proxy in China format example dockerhub (docker.io) dockerhub.azk8s.cn dock ...