本文来说一下,我们开发好的.java
文件是源码文件,并不能交给机器直接执行,需要将其变成字节码甚至是机器码文件。那么静态编译器是如何把源码转化成字节码的呢?
下图为.java
源码转化为字节码的过程。
词法解析就是通过空格分隔出单词、操作符、控制符等信息,将其形成token信息流,传递给语法解析器;在语法解析时,把词法解析得到的token信息流按照Java语法规则组装成一个语法树。
如上图虚线框中所示;在语义分析阶段,需要检查关键字的使用是否合理、类型是否合理、作用域是否正确等。当语义分析完成之后,即可以生成字节码。
字节码必须通过类加载过程加载到JVM
环境中后,才可以执行。
字节码执行的三种模式
解释执行
JIT
编译执行
JIT
编译与解释混合执行(主流JVM
默认模式)
何为JIT
编译?
动态编译(dynamic compilation)指的是“在运行时进行编译”;与之相对的是事前编译(ahead-of-time compilation,简称AOT
),也叫静态编译(static compilation)。
JIT编译(just-in-time compilation)狭义来说是当某段代码即将第一次被执行时进行编译,因而叫“即时编译”。JIT编译是动态编译的一种特例。JIT编译一词后来被泛化,时常与动态编译等价;但要注意广义与狭义的JIT编译所指的区别。
自适应动态编译(adaptive dynamic compilation)也是一种动态编译,但它通常执行的时机比JIT
编译迟,先让程序“以某种式”先运行起来,收集一些信息之后再做动态编译。这样的编译可以更加优化。
混合执行模式的优势在于解释器在启动时先解释执行,省去编译时间。随着时间推进,JVM
通过热点代码统计分析,识别高频的方法调用、循环体、公共模块等。JIT
的作用就是将Java字节码动态低编译成可以直接发送给处理器指令执行的机器码。大致流程如下:
注意:解释执行与编译执行在线上环境微妙的辩证关系。机器在热机状态可以承受的负载大于冷机状态(刚刚启动的时候),如果以热机状态的流量进行切流,可能会导致处于冷机状态的服务器因无法承受流量而假死。在生产环境发布过程中,以分批的方式进行发布,根据机器数量划分成多个批次,建议每个批次的机器数之多占到整个集群的12.5%(1/8)。曾经有这样的故障案例:某程序员在发布平台进行分批发布,在输入发布总批次数的时候,误填写成分两批发布。如果是热机状态,在正常情况下一半的机器可以勉强承载流量,但是由于刚刚启动的JVM均是解释执行,还没有进行热点代码统计和JIT
动态编译,导致机器启动之后,当前1/2发布成功的服务器马上全军覆没,此次故障说明了JIT
的存在。
下篇说类加载过程,敬请期待!