JVM_3_程序编译与代码优化
Posted AJCoder
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM_3_程序编译与代码优化相关的知识,希望对你有一定的参考价值。
1. 编译器
1.1 分类及说明
-
前端编译器: 把*.java文件转变为*.class文件 -
Javac、ECJ -
后端运行期编译器(JIT编译器): 把字节码(*.class文件)转变为机器码 -
HotSpot的C1、C2 -
静态提前编译器(AOT编译器): 把*.java文件编译成本地机器代码 -
GCJ
2. Java语法糖(编译器优化)
2.1 默认构造器
public class Candy{
}
编译成class后的代码:
public class Candy{
//这个无参构造是编译器加上的
public Candy(){
super(); //调用父类Object的无参构造方法
}
}
2.2 自动拆装箱
public class Candy{
public static void main(String[] args){
Integer x = 1;
int y = x;
}
}
编译成class后的代码:
public class Candy{
public static void main(String[] args){
Integer x = Integer.valueOf(1); //编译器自动装箱
int y = x.intValue(); //编译器自动拆箱
}
}
2.3 泛型集合取值
public class Candy{
public static void main(String[] args){
List<Integer> list = enw ArrayList<>();
list.add(10); //实际调用的是 list.add(Object o)
Integer x = list.get(0); //实际调用的是 Object obj = List.get(int index);
}
}
擦除的是字节码上的泛型信息。
2.4 可变参数
2.5 foreach循环
2.6 switch 字符串
2.7 switch 枚举
2.8 枚举类
2.9 try-with-resources
3. 运行期优化
3.1 JIT编译器
-
将 字节码转换为 机器码
3.1.1 解释器和编译器
HotSpot同时包含解释器和编译器。解释器和编译器两者各有优势:当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行。在程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码之后,可以获取更高的执行效率。因此,在整个虚拟机的执行架构中,解释器与编译器经常配合工作。
即时编译器(JIT)和解释器的区别:
-
解释器即使下次遇到相同的字节码,仍会执行重复的解释; -
JIT编译器将编译的机器码存入code cache,下次遇到相同,直接执行; -
解释器将字节码解释为针对所有平台都通用的机器码; -
JIT会根据平台类型,生成平台特定的机器码;
3.1.2 HotSpot虚拟机
内置两个即时编译器,分别称为Client Compiler和Server Compiler或者简称为C1编译器和C2编译器。
-
JVM分为Server模式和Client模式,对应的编译器也有C1(Client Complier)和C2(Server Complier)两个编译器。C1编译器注重编译的速度,C2编译器注重编译的质量。 -
不论在Server模式还是Client模式,解释器只有一个。早期的JVM中解释器只能和C1或C2中的一个混合运作(当然也可以通过设置虚拟机参数,强制只有编译器运作或只有解释器运作)。 -
在JDK1.7中,分层编译的加入,让两个编译器和一个解释器可以共同参与工作。
3.1.3 分层编译
-
第0层:编译器不工作,只有解释器解释执行程序,可触发第二层编译。 -
第1层:解释器和C1编译器共同工作。把热点字节码编译为机器码,并进行简单可靠的优化,如有必要会开启性能监测。可触发 第2层编译。 -
第2层(或第2层以上):解释器和C2编译器共同工作。把热点字节码编译为机器码,开启性能监测,并通过监测结果进行激进 优化。
在开启分层编译后,由于两个编译器的加入,许多代码会被多次编译。既通过C1得到了更高的编译速度,也通过C2得到了更高的编译质量,是JVM代码执行系统的一大进步。
3.2 即时编译
3.2.1 分层编译
-
TieredCompilation
3.2.2 方法内联
-
Inlining
3.2.3 逃逸分析
逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,称为方法逃逸。甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,称为线程逃逸。
开启逃逸分析,并查看分析结果:
-XX:+DoEscapeAnalysis +PrintEscapeAnalysis
关闭逃逸分析:
-XX:-DoEscapeAnalysis
- END -
以上是关于JVM_3_程序编译与代码优化的主要内容,如果未能解决你的问题,请参考以下文章
大数据技术之_30_JVM学习_01_JVM 位置+JVM 体系结构概览+堆体系结构概述+堆参数调优入门+JVM 的配置和优化+Tomcat 的配置和优化