jit
Java 代码首先被编译为字节码(.class),JVM 在运行时通过解释器执行字节码。当某部分的代码被频繁执行时,JIT 会将这些热点代码编译为机器码,以此来提高程序的执行效率。
那为什么 JIT 就能提高程序的执行效率呢,解释器不也是将字节码翻译为机器码交给操作系统执行吗?
解释器在执行程序时,对于每一条字节码指令,都需要进行一次解释过程,然后执行相应的机器指令。这个过程在每次执行时都会重复进行,因为解释器不会记住之前的解释结果。
与此相对,JIT 会将频繁执行的字节码编译成机器码。这个过程只发生一次。一旦字节码被编译成机器码,之后每次执行这部分代码时,直接执行对应的机器码,无需再次解释。
除此之外,JIT 生成的机器码更接近底层,能够更有效地利用 CPU 和内存等资源,同时,JIT 能够在运行时根据实际情况对代码进行优化(如内联、循环展开、分支预测优化等),这些优化是在机器码级别上进行的,可以显著提升执行效率。
Java 的执行过程分为两步,第一步由 javac 将源码编译成字节码,在这个过程中会进行词法分析、语法分析、语义分析。
第二步,解释器会逐行解释字节码并执行,在解释执行的过程中,JVM 会对程序运行时的信息进行收集,在这些信息的基础上,JIT 会逐渐发挥作用,它会把字节码编译成机器码,但不是所有的代码都会被编译,只有被 JVM 认定为热点代码,才会被编译。
JVM 中有一个阈值,当方法或者代码块的在一定时间内的调用次数超过这个阈值时就会被认定为热点代码,然后编译存入 codeCache 中。当下次执行时,再遇到这段代码,就会从 codeCache 中直接读取机器码,然后执行,以此来提升程序运行的性能。
为什么不一开始就把所有字节码翻译成机器码?
首先JVM是运行字节码的,这是他能够跨平台运行的核心,所以必须运行字节码,而运行字节码的过程中,如果遇到一条字节码就把他翻译成机器码并存储下来,这是需要空间存储的,如果是冷门代码,得不偿失
JIT优化手段:
锁消除:如果synchronized锁住的区域经过JIT分析发现不会产生线程安全问题,会把锁消除掉
标量替换:某对象没有逃逸出方法,那么这个对象的字段可以拆成标量


栈上分配:对象没有逃逸出方法,就可以在栈上分配,本质其实是标量替换
方法内联:简单的方法可以直接内联到调用处


逃逸分析:
全局逃逸:对象超出方法或线程范围,比如存储在静态字段或者作为方法的返回值
参数逃逸:对象被作为参数传毒,但方法调用期间不会全局逃逸
无逃逸:对象没有逃逸出方法
