网站建设与管理的未来规划方案,手机百度高级搜索,学软件工程可以从事什么工作,中国互联网行业的发展趋势一、概述 
Java程序运行时#xff0c;JVM会加载.class字节码文件#xff0c;但是字节码并不能直接运行在操作系统之上#xff0c;而JVM中的执行引擎就是负责将字节码转化为对应平台的机器码让CPU运行的组件。 
执行引擎是JVM核心的组成部分之一。可以把JVM架构分成三部分JVM会加载.class字节码文件但是字节码并不能直接运行在操作系统之上而JVM中的执行引擎就是负责将字节码转化为对应平台的机器码让CPU运行的组件。 
执行引擎是JVM核心的组成部分之一。可以把JVM架构分成三部分如下图所示 执行引擎位于JVM的最下层图中虚线框部分可以粗略地看到执行引擎负责和运行时数据区交互。 二、计算机语言的发展史 
在讲解执行引擎之前需要知道什么是机器码、汇编语言、高级语言以及为什么会有Java字节码的出现。 2.1 机器码 
各种用 0 和 1 组成的二进制编码方式表示的指令叫作机器指令码简称机器码。 
计算机发展的初始阶段人们就用机器码编写程序我们也称为机器语言。机器语言虽然能够被计算机理解和接受但由于可读性差不便于人类读写并且用它编程容易出差错。使用机器码编写的程序一经输入计算机CPU可以直接读取运行因此和其他语言编的程序相比执行速度最快。机器码与CPU紧密相关所以不同种类的CPU所对应的机器码也就不同。 2.2 汇编语言 
由于机器码是由0和1组成的二进制序列可读性实在太差于是人们发明了指令。 
指令就是把机器码中特定的0和1序列简化成对应的指令一般为英文简写如mov、inc等可读性稍好这就是我们常说的汇编语言。在汇编语言中用助记符 (Mnemonics) 代替机器码的操作码用地址符号 (Symbol) 或标号 (Label) 代替指令或操作数的地址。 
不同的硬件平台各自支持的指令是有差别的。因此每个平台所支持的指令称为对应平台的指令集如常见的x86指令集对应的是x86架构的平台ARM指令集对应的是ARM架构的平台。不同平台之间指令不可以直接移植。 
由于计算机只认识机器码所以用汇编语言编写的程序还必须经过汇编器转换为机器语言计算机才能识别和执行。 2.3 高级语言 
为了使计算机用户编程序更容易些后来就出现了各种高级计算机语言。比如C、C等更容易让人识别的语言。 
高级语言则相对汇编语言更易于编写有更好的可读性一般编译器会将高级语言转换成汇编语言然后再由汇编器转换为机器指令由计算机执行。 2.4 字节码 
字节码是一种中间状态中间码的二进制代码文件需要转译后才能成为机器码。Java 程序可以通过编译器将源码编译成 Java 字节码特定平台上的虚拟机将字节码转译为可以直接执行的指令也就实现了跨平台性。如下图所示 三、执行引擎工作过程 执行引擎在执行过程中需要执行什么样的字节码指令取决于PC寄存器程序计数器每执行完一项指令操作之后PC寄存器会更新下一条需要执行的指令地址方法执行过程中执行引擎可能会通过局部变量表中的对象引用准确定位到 Java 堆中的对象实例信息以及通过对象头中的元数据信息定位到目标对象的类型信息。 Java执行引擎包括以下组成部分 解释器JIT编译器垃圾收集器 3.1 解释器 
解释器就是一个运行时的“翻译者”将字节码指令翻译为对应平台的本地机器指令由CPU执行当一条指令执行完成后再根据PC寄存器中记录的下一条指令执行解释操作。 
JVM设计者的初衷是为了满足Java程序实现跨平台特性因此避免采用静态编译的方式直接生成机器码从而诞生了实现解释器在运行时采用逐行解释字节码执行程序的想法。 3.2 JITJust-In-Time编译器 
当执行某些频繁被调用的代码比如for循环中的代码时如果按照解释执行效率非常低这种被频繁调用的代码成为热点代码。为了提高热点代码的执行效率在运行时JIT编译器则会将这些代码编译成与本地平台有关的机器码并进行各种层次的优化。 
JIT的构成组件包括 中间代码生成器——生成中间代码代码优化器——优化中间代码目标代码生成器——生成机器码或本地代码分析器——负责查找热点代码 3.2.1 JIT编译器类型 
在 Hotspot 虚拟机中内置了两种JIT编译器 C1编译器主要关注点在于局部性能优化适用于执行时间短或对启动性能有要求的程序如GUI应用C1编译器也被称为Client Compiler。C2编译器为长期运行的服务端应用程序做性能优化的编译器适用于执行时间较长或对峰值性能有要求的程序C2编译器也被称为Server Compiler。 Graal编译器用Java实现的JIT编译器JDK10中引入具体信息参考 JEP 317: Experimental Java-Based JIT CompilerJDK17中移除移除原因参考 JEP 410: Remove the Experimental AOT and JIT Compiler 3.2.2 分层编译 
在 Java7 引入了分层编译这种方式综合了 C1 的启动优势和 C2 的峰值性能优势。分层编译将 JVM 的执行状态分为5个层次 第0层程序解释执行默认开启性能监控Profiling如果不开启可触发第二层编译第1层C1编译将字节码编译成本地代码进行简单可靠的优化不开启Profiling第2层C1编译开启Profiling仅执行带方法调用次数和循环回边执行次数Profiling的C1编译第3层C1编译执行所有带Profiling的C1编译第4层C2编译将字节码编译为本地代码但会启用一下编译耗时较长的优化甚至会根据性能监控信息进行一些不可靠的激进优化。 Java8 中默认开启分层编译-XX:-TieredCompilation 参数可关闭分层编译只使用C2编译如果只使用C1编译可设置参数 -XX:TieredStopAtLevel1。 
-Xint参数可设置为强制解释器模式运行-Xcomp可设置为强制运行JIT编译模式。 3.2.3 热点代码探测 
Hotspot 虚拟机判定热点代码基于2种计数器进行方法调用计数器和回边计数器只有代码符合标准并达到设置的阈值才会进行JIT编译优化。 1方法调用计数器 
当某个方法调用次数达到阈值就会触发JIT编译优化。 
jinfo -flag CompileThreshold 或者 java -XX:PrintFlagsFinal -version 命令可查看方法调用次数阈值客户端模式下默认值为1500服务端模式下默认值为10000。 2回边计数器 
用于统计方法体中循环体代码执行次数字节码中遇到控制流向后跳转的指令称为“回边”Back Edge用于计算是否为热点代码的阈值。 计算公式如下   回边计数器阈值  方法调用计数器阈值CompileThreshold*OSR比率OnStackReplacePercentage-解释器监控比例InterpreterProfilePercentage/ 100  java -XX:PrintFlagsFinal -version 命令可查看相关参数 根据图中显示的各参数的默认值可以计算出回边计数器阈值为1000 * (140 - 33)  10700 3.2.4 编译优化技术 
1方法内联  
方法内联的优化行为是将目标方法的代码复制到发起调用的方法中避免真实方法调用。 
private int add(int a, int b, int c, int d) {return addInt1(a, b)  addInt2(c, d);
}
private int addInt1(int a, int b) {return a  b;
}
private int addInt2(int a, int b) {return a  b;
} 
例如上面的代码如果被检测为热点代码则会被优化为以下代码 
private int add(int a, int b, int c, int d) {return a  b  c  d;
} 
热点方法不一定都会被内联优化只有当方法体大小小于参数 -XX:FreqInlineSize 值默认325字节才会进行内联非热点方法当方法体小于参数 -XX:MaxInlineSize 值默认35字节才会进行内联。 相关性能调优  减小热点方法检测阈值增加内联方法体阈值缺点则是会增加内存占用尽量避免在一个方法体内写入大量代码习惯使用小方法体尽量使用final private static 关键字修饰方法代码优化时因为继承需要额外的类型检查。 2锁消除 
当方法中的局部方法中创建的对象只能被当前线程访问时不存在锁竞争JIT编译会对这个对象的方法进行锁消除。 
参数 -XX:EliminateLocks 可以开启锁消除默认开启-XX:-EliminateLocks 则是关闭锁消除。 3锁粗化 
如果检测到同一个对象执行了连续的加锁和解锁操作则会将这一系列操作合并成一个更大的锁从而提升程序运行效率。 4逃逸分析 
JIT编译器会对热点代码中的对象进行逃逸分析分析该对象动态作用域当被传递到其他方法中称为方法逃逸当能被外部方法所引用则为线程逃逸。 
不逃逸 到 方法逃逸 再到 线程逃逸逃逸程度由低到高。 
逃逸分析可以通过参数 -XX:DoEscapeAnalysis开启jdk1.8默认开启或 -XX:-DoEscapeAnalysis 关闭。 
关闭逃逸分析会导致对象分配到堆中频繁触发垃圾回收导致代码运行慢。 5标量替换 
当确定对象不会逃逸出线程之外该对象则会被分配到栈上对象分配到栈需要进行成员变量拆分这种优化技术叫做标量替换。标量替换需要开启逃逸分析。 
标量替换可以通过参数 -XX:EliminateAllocations开启jdk1.8默认开启或-XX:EliminateAllocations关闭 3.3 垃圾收集器 
Java的一个主要特点就是开发人员不需要过分关注对象的内存管理无用对象的销毁和空间释放都交由JVM的垃圾收集器处理。这减轻了编程负担提高了编程效率但垃圾回收也会影响程序的性能。 
详细介绍见上章。 四、总结 
JVM中的执行引擎是JVM的重要组成部分之一主要负责将字节码指令翻译成机器码指令。 
执行引擎包括解释器JIT解释器和垃圾收集器。 
解释器就是运行时的“翻译者”将字节码解释为机器指令。 
但是某些频繁执行的热点代码依然采用解释执行的话会导致程序执行很慢JIT编译器则是负责将热点代码编译分层优化成本地机器码。 
垃圾收集器则负责无用对象的销毁释放内存空间。