原创申明:本文由公众号【猿灯塔】原创,转载请说明出处标注

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_CreateJavaVMJNI_GetDefaultJavaVMInitArgs绑定到InvocationFunctions变量的CreateJavaVMGetDefaultJavaVMInitArgs函数指针变量上;

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启动流程的更多相关文章

  1. Tomcat源码分析之—具体启动流程分析

    从Tomcat启动调用栈可知,Bootstrap类的main方法为整个Tomcat的入口,在init初始化Bootstrap类的时候为设置Catalina的工作路径也就是Catalina_HOME信息 ...

  2. Jvm(jdk8)源码分析1-java命令启动流程详解

    JDK8加载源码分析 1.概述 现在大多数互联网公司都是使用java技术体系搭建自己的系统,所以对java开发工程师以及java系统架构师的需求非常的多,虽然普遍的要求都是需要熟悉各种java开发框架 ...

  3. [Abp vNext 源码分析] - 1. 框架启动流程分析

    一.简要说明 本篇文章主要剖析与讲解 Abp vNext 在 Web API 项目下的启动流程,让大家了解整个 Abp vNext 框架是如何运作的.总的来说 ,Abp vNext 比起 ABP 框架 ...

  4. Tomcat源码分析(从启动流程到请求处理)

    Tomcat 8.5下载地址 https://tomcat.apache.org/download-80.cgi Tomcat启动流程 Tomcat源码目录 catalina目录 catalina包含 ...

  5. Android进阶系列之源码分析Activity的启动流程

    美女镇楼,辟邪! 源码,是一个程序猿前进路上一个大的而又不得不去翻越障碍,我讨厌源码,看着一大堆.5000多行,要看完得啥时候去了啊.不过做安卓的总有这一天,自从踏上这条不归路,我就认命了.好吧,我慢 ...

  6. JVM源码分析-类加载场景实例分析

    A类调用B类的静态方法,除了加载B类,但是B类的一个未被调用的方法间接使用到的C类却也被加载了,这个有意思的场景来自一个提问:方法中使用的类型为何在未调用时尝试加载?. 场景如下: public cl ...

  7. JVM源码分析之堆外内存完全解读

    JVM源码分析之堆外内存完全解读   寒泉子 2016-01-15 17:26:16 浏览6837 评论0 阿里技术协会 摘要: 概述 广义的堆外内存 说到堆外内存,那大家肯定想到堆内内存,这也是我们 ...

  8. JVM源码分析之Metaspace解密

        概述 metaspace,顾名思义,元数据空间,专门用来存元数据的,它是jdk8里特有的数据结构用来替代perm,这块空间很有自己的特点,前段时间公司这块的问题太多了,主要是因为升级了中间件所 ...

  9. JVM源码分析-JVM源码编译与调试

    要分析JVM的源码,结合资料直接阅读是一种方式,但是遇到一些想不通的场景,必须要结合调试,查看执行路径以及参数具体的值,才能搞得明白.所以我们先来把JVM的源码进行编译,并能够使用GDB进行调试. 编 ...

随机推荐

  1. Java实现LeetCode_0020_ValidParentheses

    package javaLeetCode.primary; import java.util.Scanner; import java.util.Stack; public class ValidPa ...

  2. java实现排列为平方数

    ** 排列为平方数** 若干不同的数字,排列组合后能产生多少个平方数? 下面的代码解决了这个问题. 对于:1,6,9 排列后,可产生3个平方数: 169 196 961 请阅读下面的代码,填写缺失的部 ...

  3. Java实现第八届蓝桥杯取数位

    取数位 求1个整数的第k位数字有很多种方法. 以下的方法就是一种. 还有一个答案:f(x/10,k--) public class Main { static int len(int x){ // 返 ...

  4. JSP+SSM+Mysql实现的学生成绩管理系统

    项目简介 项目来源于:https://gitee.com/z77z/StuSystem 本系统是基于JSP+SSM+Mysql实现的学生成绩管理系统.主要实现的功能有教师管理.学生管理.课程管理.学生 ...

  5. Spring Boot 集成 Swagger 构建接口文档

    在应用开发过程中经常需要对其他应用或者客户端提供 RESTful API 接口,尤其是在版本快速迭代的开发过程中,修改接口的同时还需要同步修改对应的接口文档,这使我们总是做着重复的工作,并且如果忘记修 ...

  6. 深入浅出-TCP/IP协议族剖析&&Socket

    Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0 #简介 该篇文章主要回顾–TCP/I ...

  7. 时间序列神器之争:prophet VS lstm

    一.需求背景 我们福禄网络致力于为广大用户提供智能化充值服务,包括各类通信充值卡(比如移动.联通.电信的话费及流量充值).游戏类充值卡(比如王者荣耀.吃鸡类点券.AppleStore充值.Q币.斗鱼币 ...

  8. .net core3.1 abp动态菜单和动态权限(思路) (二)

    ps:本文需要先把abp的源码下载一份来下,跟着一起找实现,更容易懂 在abp中,对于权限和菜单使用静态来管理,菜单的加载是在登陆页面的地方(具体是怎么知道的,浏览器按F12,然后去sources中去 ...

  9. 君荣一卡通软件mysql转sqlserver 教程

    Mysql数据库转sql数据库方法 注意:新建的SQL数据库一得先登录一次后再做迁移!!!!特别注意 如果客户以前安装的是mysql数据库,现在希望把mysql数据库转换的sql数据库,方法如下: 1 ...

  10. Flutter学习笔记(31)--异步更新UI

    如需转载,请注明出处:Flutter学习笔记(31)--异步更新UI 大家都知道,子线程不能操作UI控件,在我们Android的日常开发中,经常会遇到网络请求数据通过线程间通信,将数据发送到UI线程中 ...