[六]前后端编译

以下所有内容来自于 《深入理解 Java 虚拟机》这本书的理解和回顾,非照抄原文,肯定有错误,也有故意致错,一切皆为方便理解

#编译器

  • 前端编译器:JDK Javac ,Eclipse JDT EJC
  • 即时编译器:虚拟机中的 C1,C2,Grral

# 前端编译器

  • 前端编译器的优化主要是提升用户的效率,比如许多的语法糖,提高了开发人员的效率,在前端编译器中会把他们还原成基本的 Java 语法,对于实际程序的运行效率几乎没有作用

  • 本身是由 Java 语言编写的程序

  • class 文件是和编译器实现相关的,所以在类加载时需要对 class 文件校验

编译过程: 一个准备,三个处理

[六]前后端编译

1.解析与填充符号表:

  • 词法,语法分析,构造抽象语法树
  • 填充符号表,产生符号信息和符号地址,用于后续编译检查

2.注解处理

3.分析与字节码生成:

  • 标注检查,对程序静态信息进行检查
  • 数据流及控制流分析,对程序动态运行过程检查
  • 解语法糖
  • 字节码生成

语法糖

提供一些特殊语法提高代码开发,比如泛型,,自动装箱,遍历循环,条件编译等等

# 即时编译器(后端编译器)

即时编译器工作在运行时,前面讲到的 类加载内存布局垃圾收集,都是外围设备,编译器才是核心,是机器的发动机,已经分析好的代码会源源不断的送给编译器,执行过程中的数据变量也已经准备到各个空间,即时编译器的优劣直接影响程序的运行效率

Java 程序最初是通过解释器解释运行,发现某段代码频繁执行,就把他转换成本地机器码,完成这个转换的后端编译器就叫做即时编译器

问题:

1.为什么 Java 虚拟机 要使用解释器和编译器混合进行?

热点代码 编译成机器码,提高效率

2.为什么 Java 虚拟机要实现多个即时编译器?c1,c2,grral?

应对不同的场景,没有什么是完美的,即时编译器也有缺点,它在运行时会占用用户程序的运行时间,c1是客户端编译器(轻量级),c2是服务端编译器(重量级),后者有更激烈的优化措施,更高的编译效率,更高的占用时间,根据需求自由搭配,grral 则是新一代编译器,目标是代替C2,也是未来 Graal 虚拟机的核心(Grral 虚拟机 = hotspt 虚拟机 + graal 编译器)

3.程序何时使用解释器,何时使用编译器?

分层编译:在JDK 7 的服务端模式下,默认开启分层编译,就是根据程序的复杂度,虚拟机自行搭配不同的编译器,以实现效率和时间的平衡

4.哪些程序会被编译成本地代码?如何编译?

自然是热点代码喽,包括:

  • 多次调用的方法
  • 被多次执行的循环体

如何找到这些方法:

  • 基于采样的热点探测:如果某个方法经常出现在栈顶,就列为热点方法,简单高效,精确度低,例如线程堵塞
  • 基于计数器的热点检测:为每个方法建立计数器,统计调用次数,复杂准确

Java 虚拟机采用第二种方法,为每个方法建立两个计数器,一个方法调用计数器,一个回边计数器(统计方法中循环体执行次数),超过规定阈值设为热点代码

编译过程:

[六]前后端编译

编译完成后的代码会进行 栈上提换,偷梁换柱,把原来的代码接口换成编译后的本地码

5.前面提到激进激进编译?那编译失败怎么办?

逃生门:由于激进编译会存在一定风险,里面使用了一些玄学理论,比如正常情况下应该是怎样,然后按照这种情况编译,若不是正常情况,就会编译失败,或者编译出奇怪的代码,为防止这种情况,设计了逃生门,当编译的这段程序异常时,则停止这段本地代码的执行,继续使用解释器执行原来的代码

6,编译优化技术

在这之中,也产生了各种各样的优化技术提高编译效率,或者解决编译出现的问题

比如:方法内联,逃逸分析。数组边界消除等等