《深入理解JAVA虚拟机(第2版)》- 第10章 - 学习笔记

第10章 早期(编译期)优化

10.1 概述

Java语言的编译期 是一个不确定的操作过程。之所以这么说是因为有如下三类编译过程:

  1. 前端编译器(准确来说应该是编译器的前端)将java文件编译成class文件的过程。
  2. 即时编译器(JIT)将字节码编译成本地机器码的过程。
  3. 静态提前编译器(AOT编译器,Ahead Of Time Compiler)直接将java文件编译成本地机器码的过程。

如上描述的三类编译过程有代表性的编译器如下:

  • 前端编译器:Sun的Javac。
  • JIT编译器:HotSpot VM的C1、C2编译器。
  • AOT编译器:GNU Compiler for the Java。

10.2 Javac编译器

Javac编译器是纯Java代码编写的程序。它的编译过程大致可以分为3个过程,如下图:

  • 解析与填充符号表过程
  • 插入式注解处理器的注解处理过程
  • 分析及字节码生成

10.2.1 解析与填充符号表过程

  1. 解析

    解析分为两个过程词法分析与语法分析:

    • 词法分析:词法分析是将源代码中的字符流转变为Token(标记)集合的过程,其中字符是编程中的最小单位,Token(标记)是编译过程中的最小单位(不可再拆分)。变量名、字面量、运算符都可作为Token(标记),例如:int a = b + c,这里就存在6个Token(int、a、=、b、c)。
    • 语法分析:词法分析是基于Token生成抽象语法大树(Abstract Syntax Tree,AST)的过程。
    • 抽象语法树是用来描述程序代码语法结构的树形表现形式,每个节点都是一个语法结构,例如:包、类、接口、修饰符、运算符、返回值甚至包括注解。
  2. 填充符号表

    符号表是由一组符号地址和符号信息组成个表格。

    符号表应用于编译各个不同阶段,如下:

    • 在语义分析阶段,基于符号表可以进行语义检查(例如检查一个名字的使用是否和原来的说明一致)和中间代码生成。
    • 在目标代码生成阶段,当对符号名进行地址分配时,符号表作为地址分配的依据。

10.2.2 插入式注解处理器的注解处理过程

当插入式注解处理器的注解处理过程对AST的结构进行了修改,那就需要退回到解释与填充符号表过程重新开始,直到所有插入式注解处理器都没有再对AST的结构再进行修改为止,每一轮称为一个Round。

10.2.3 分析及字节码生成

  1. 分析

    这里的分析指的是语义分析,主要的任务是对结构正确的源程序进行上下文有关性质的审查,例如:类型价差。

    语义分析分为两个步骤:

    • 标注检查:标注检查包括诸如变量使用前是否声明过,变量与赋值的类型是否一致等。在标注检查这个过程中,有一个重要的动作------常量折叠,例如:int a = 1 + 2,经过常量折叠变为 int a = 3。
    • 数据及控制流分析:数据及控制流分析是对程序上下文逻辑的进一步验证,例如:方法的每条路径是否都有返回值、所有受检查的异常是否都被正确处理了。
  2. 解语法糖

    所谓解语法糖就是将语法糖还原为简单的基础语法结构

  3. 字节码生成

    字节码生成过程是将个步骤生成的信息(例如:信息表、语法树)转换为字节码并写到磁盘上,这个过程还增加了少量的代码增加和转换工作。实例构造器的<init>()方法和类构造器的<client>()都是在这个过程生成的。

10.3 语法糖的味道

  1. 自动装箱和自动拆箱,编译之后被转化成了对应的包装和还原方法。

  2. 循环遍历,编译后被还原成迭代器遍历。

  3. 变长参数,在调用的时候变成一个数组类型的参数。

  4. 泛型,本质是参数类型化的引用。实现泛型的方式有:类型膨胀和类型擦除。

    • 类型膨胀

      C#语言的泛型类,例如:List<int>,是真实存在的,有自己的类型数据和虚方法表,这种泛型的实现的方式就是类型膨胀。采用类型膨胀方式实现的泛型是真正的泛型

    • 类型擦除

    Java语言的泛型类,只存在于源码中,编译之后就会转换为原生类型,并在相应的位置上插入强制类型转换,这种泛型的实现方式就是类型擦除。采用类型擦除方式实现的泛型称为伪泛型

  5. 条件编译,Java采用的是条件为常量的if语句来实现的,如:if (true) { ... }

上一篇:《深入理解JAVA虚拟机(第2版)》- 第8章 - 学习笔记

下一篇:《深入理解JAVA虚拟机(第2版)》- 第11章 - 学习笔记

相关推荐
Arva .5 分钟前
ConcurrentHashMap 的线程安全实现
java·开发语言
听风吟丶15 分钟前
Java 9+ 模块化系统(Jigsaw)实战:从 Jar 地狱到模块解耦的架构升级
java·架构·jar
昂子的博客16 分钟前
Redis缓存 更新策略 双写一致 缓存穿透 击穿 雪崩 解决方案... 一篇文章带你学透
java·数据库·redis·后端·spring·缓存
百***688218 分钟前
SpringBoot中Get请求和POST请求接收参数详解
java·spring boot·spring
摇滚侠23 分钟前
Vue 项目实战《尚医通》,预约挂号的路由与静态搭建,笔记36
javascript·vue.js·笔记
三品吉他手会点灯31 分钟前
STM32F103学习笔记-16-RCC(第4节)-使用 HSI 配置系统时钟并用 MCO 监控系统时钟
笔记·stm32·单片机·嵌入式硬件·学习
百***416632 分钟前
Java MySQL 连接
java·mysql·adb
Jayden37 分钟前
synchronized全解析:从锁升级到性能优化,彻底掌握Java内置锁
java·synchronized·synchronized面试·synchronized扫盲
Lester_11011 小时前
嵌入式学习笔记 - 关于看门狗定时器的喂狗的操作放在中断还是放在主循环
笔记·单片机·学习
任子菲阳1 小时前
学Java第四十五天——斗地主小游戏创作
java·开发语言·windows