Java代码从编译到执行的历程 | 编译流程,javac,JIT

不可不知的Java代码从编译到执行的历程

1、程序编译执行流程

一般情况下,一个程序从编译到执行,有以下这些阶段:

image-20200111220711082

2、Java程序编译类型

而在Java中,有几种编译模式,如果用的是前端编译+后端编译,则把以上流程进行划分,常用的组合是:javac前端编译器+JIT后端编译器:

image-20200111220207451

而在执行过程中,会进行混合模式执行:部分函数会解释执行,部分会编译执行。

2.1、Java程序编译执行过程

如下图,为Java代码从编译到执行的过程:

image-20200111220440500

  • 在前端编译时,把Java源文件编译为Class文件;

  • 在解释执行时,会收集运行数据,根据热点代码进行JIT编译优化,生成本地机器码,加快程序的执行。

更多关于类加载器,系统初始化,以及加载Class文件到JVM的过程,参考之前发布的两篇文章:

3、javac

3.1、javac中的主要类

image-20200117001110775

3.2、javac主要处理流程

主要处理流程入口:JavaCompiler.compile()

image-20200116230536483

compile2()方法中的默认编译策略:

image-20200116224550074

  1. initProcessAnnotations(processors)

    1. 准备过程:初始化插入式注解处理器
  2. parseFiles(sourceFileObjects):解析步骤

    1. 词法分析:将字符流转换为标记(Token)集合(符号流);
    2. 语法分析:根据token序列构造抽象语法树,后续操作都建立在语法树上,语法分析相关类:Parser
  3. enterTrees:填充符号表

  4. processAnnotations()

    1. 注解处理器的执行过程
  5. delegateCompiler.compile2():分析及字节码生成

    1. attribute:语义分析过程,标注检查,主要包括诸如变量使用前是否已被声明、变量与赋值之间的数据类型是否能够匹配等;同时会进行常量折叠(int a = 1+2 折叠为 int a =3);

    2. flow:语义分析过程,数据及控制流分析。这一步是对程序上下文逻辑更进一步的验证,可以检查出诸如程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否所有的受检验异常都被正确处理了等问题。

      1. final类型的局部变量就是通过在这一步分析来保证不被重新赋值的;因为局部变量不像类变量,在Class文件中有CONSTANT_Fieldref_info符号引用,记录了访问标志。

    3. desugar:解除语法糖

    4. generage:生成字节码,同时会进行少量代码添加和转换工作。如:

      1. 添加实例构造器()方法和类构造器()方法;
      2. 把字符串相加操作替换为StringBuffer或者StringBuilder(JDK 1.5+);

References

What is JIT in Java?

Compilation and Execution of a Java Program

Javac编译器详解

Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用

arthinking wechat
欢迎关注itzhai公众号,获取更多最新的文章