java虚拟机启动器,java虚拟机运行java程序的基本过程

  java虚拟机启动器,java虚拟机运行java程序的基本过程

  一、前言二。Java虚拟机(1)配置JVM加载环境(2)分析命令行参数(3)执行main方法1,创建新的JVM实例2,加载入口类3,找到main方法4,执行main方法3,分析字节码(1)解释字节码1,基于栈指令集2,编译字节码1和基于寄存器指令集2的C1。

  00-1010我们在编写Java应用的时候,很少关注Java程序是如何被操作系统运行和管理调度的。带着好奇心,探索Java虚拟机的启动过程。

  00-1010从Java源代码、Java字节码、Java虚拟机、操作系统四个角度分解启动过程。

  public class hello world { public static void main(String[]args){ system . out . println( hello world!);}}

目录

利用Java环境提供的可执行命令javac将源代码编译成字节码文件。编译后的字节码文件是独立于平台的,可以跨平台运行。注意,discribe javac命令是一个独立的编译应用程序。当源代码被编译时,该过程终止。java命令启动的虚拟机进程的编译过程是将字节码指令编译成汇编指令(二进制指令)。

 

  

一、序言

Java字节码不能直接在操作系统上创建进程,需要借助已启动的虚拟机进程来解析字节码。处理字节码有两种常见的方法:解释型和编译型。

 

  命令行中的每个java命令都会启动一个Java虚拟机进程,每个虚拟机都是相互独立的。虚拟机进程由命令行参数配置。

  Java虚拟机准备启动后,可以依次解析字节码指令,正式运行Java代码部分。

  00-1010操作系统通过进程管理和调度Java虚拟机,无法感知虚拟机间接解析Java字节码。Java字节码通过虚拟机的抽象运行在操作系统上。

  00-1010运行Java应用时,需要先安装Java环境。但是,安装的Java环境和Java应用程序有什么关系呢?Java应用程序是如何运行的?让我们找出答案。

  二进制可执行程序${JAVA_HOME}/bin/java用C语言编写,由GCC编译器编译。探究Java虚拟机的运行原理,首先需要找到相应的源代码。

  当您安装Java环境时,您会看到一个src.zip压缩文件。解压后,里面的launcher/java.c文件就是可执行java命令的主要源代码。

  虚拟机的启动入口位于launcher/java.c的main方法中整个过程分为以下几个步骤:配置JVM加载环境;正在解析虚拟机参数;设置线程堆栈大小;执行Java main方法

  00-1010从操作系统加载环境变量、硬件信息等运行环境信息,为后续创建JVM进程做准备。

  00-1010加载JVM环境后,需要在启动时解析命令行参数。这个过程是通过ParseArguments方法实现的,调用AddOption方法将解析后的参数保存到JavaVMOption中。

  例如,在此步骤中解析公共JavaVMOption参数:

  -Xms:设置InitialHeapSize值,这也是堆的最小值;-Xmx:设置最大MaxHeapSize堆的;

  JVM调优参数的分析在这一步完成。

  00-1010线程栈大小确定后,通过ContinueInNewThread方法创建一个新线程,执行JavaMain函数。大致过程如下:

  00-1010初始化JVM方法调用InvocationFunctions的CreateJavaVM方法,即调用JVM.dll函数JNI_CreateJavaVM创建新的JVM实例,这是一个复杂的过程。

  h4>2、加载入口类通常在命令行中运行如下命令即指明入口类路径

  

# 直接指名入口类路径java HelloWorld.class# 通过包类配置入口类路径java -jar HelloWorld.jar

 

  

3、查找main方法

通过GetStaticMethodID方法查找指定main方法名的静态方法。

 

  

 

  

4、执行main方法

通过JavaCalls::call回调执行main方法。需要注意的是,这里执行main方法不是Java语言的方法,是经过虚拟机解释(或者编译)后,操作系统能够理解的二进制可执行方法。

 

  

 

  

三、解析字节码

 

  

(一)解释字节码

 

  

1、基于栈指令集

iconst_1 将 1 放入栈顶iconst_1 将 1 放入栈顶iadd 将栈顶的 2 个数相加后结果放入栈顶istore_0 将相加的结果放入局部变量表

基于栈的指令集优点是虚拟机解释器是可跨平台移植的,换句话说不同平台的虚拟机解释器代码可以复用。

 

  

 

  

2、基于寄存器指令集

mov eax,1 把 EAX 寄存器的值设为 1add eax,1 再把这个值加 1 ,结果保存在了 EAX 寄存器

基于寄存器指令集的优点是执行速度相对于栈较快,原因是出栈入栈本身就涉及了大量的指令,而且栈是在内存中实现的,更底层的汇编指令性能更高。

 

  基于寄存器指令集的缺点是虚拟机解释器是不可跨平台移植,需要针对不同平台的虚拟机做不同实现。考虑到不同平台已经使用不同的虚拟机程序,因此此过程多用户透明。

  虚拟机通过解释器来翻译字节码文件中的指令比较顺其自然,可是对于服务器端高频执行的程序来说,中间的翻译过程相对耗时。解释字节码的方式适用于对启动性能要求高,并且执行频率较低的应用程序。

  

 

  

(二)编译字节码

最初,JVM 中的字节码是由解释器( Interpreter )完成编译的,当虚拟机发现某个方法或代码块的运行特别频繁的时候,就会把这些代码认定为热点代码

 

  为了提高热点代码的执行效率,在运行时,即时编译器(JIT,Just In Time)会把这些代码编译成与本地平台相关的机器码,并进行各层次的优化,然后保存到内存中。

  在 HotSpot 虚拟机中,内置了两种 JIT,分别为C1 编译器C2 编译器,这两个编译器的编译过程是不一样的。

  

 

  

1、C1 编译器

C1 编译器是一个简单快速的编译器,主要的关注点在于局部性的优化,适用于执行时间较短或对启动性能有要求的程序,也称为Client Compiler,例如,GUI 应用对界面启动速度就有一定要求。

 

  

 

  

2、C2 编译器

C2 编译器是为长期运行的服务器端应用程序做性能调优的编译器,适用于执行时间较长或对峰值性能有要求的程序,也称为Server Compiler,例如,服务器上长期运行的 Java 应用对稳定运行就有一定的要求。

 

  

 

  

3、分层编译

分层编译将 JVM 的执行状态分为了 5 个层次:

 

  

第 0 层:程序解释执行,默认开启性能监控功能(Profiling),如果不开启,可触发第二层编译;第 1 层:可称为 C1 编译,将字节码编译为本地代码,进行简单、可靠的优化,不开启 Profiling;第 2 层:也称为 C1 编译,开启 Profiling,仅执行带方法调用次数和循环回边执行次数 profiling 的 C1 编译;第 3 层:也称为 C1 编译,执行所有带 Profiling 的 C1 编译;第 4 层:可称为 C2 编译,也是将字节码编译为本地代码,但是会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。

 

  

通常情况下,C2 的执行效率比 C1 高出30%以上。

 

  在 Java8 中,默认开启分层编译。如果只想开启 C2,可以关闭分层编译(-XX:-TieredCompilation),如果只想用 C1,可以在打开分层编译的同时,使用参数:-XX:TieredStopAtLevel=1

  通过 java -version命令行可以查看到当前虚拟机解析字节码的方式,mixed mode表示既有解释模式也有即是编译模式。

  

java version "1.8.0_261"Java(TM) SE Runtime Environment (build 1.8.0_261-b12)Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, mixed mode)

mixed mode代表是默认的混合编译模式,除了这种模式外,我们还可以使用-Xint参数强制虚拟机运行于只有解释器的编译模式下;也可以使用参数-Xcomp强制虚拟机运行于只有 JIT 的编译模式下。

 

  仅使用解释模式

  通过命令java -Xint -version设置仅使用解释模式,interpreted mode表示解释模式。

  

java version "1.8.0_261"Java(TM) SE Runtime Environment (build 1.8.0_261-b12)Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, interpreted mode)

仅使用编译模式

 

  通过命令java -Xcomp -version设置仅使用编译模式,compiled mode表示编译模式。在编译模式下,程序启动能感觉到明显的卡顿。

  

java version "1.8.0_261"Java(TM) SE Runtime Environment (build 1.8.0_261-b12)Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, compiled mode)

 

  

四、小结

通过对Java虚拟机启动过程的解析,特别是即时编译环节的理解,Java应用运行并不慢。当应用中热点代码普遍被编译成汇编指令(二进制可执行命令)存放于内存中时,可近似达到C语言原生程序的运行速度。

 

  随着算力与内存成本日渐降低,通过空间复杂度置换时间复杂度的策略显然是合理的,使用Java语言编写需求万千变化的应用是第一选择:既有跨平台、内存安全、框架生态丰富的优点,也在运行效率方面积极改善,这种折中选择与市场反馈保持一致。

  到此这篇关于Java虚拟机启动过程解析的文章就介绍到这了,更多相关Java虚拟机启动内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: