逃逸分析
逃逸分析并不是直接的优化手段,而是一个代码分析,通过动态分析对象的作用域,为其它优化手段如栈上分配、标量替换和锁消除等提供依据,发生逃逸行为的情况有两种:方法逃逸和线程逃逸。
- 方法逃逸:当一个对象在方法中定义之后,作为参数传递到其它方法中。
- 线程逃逸:如类变量或实例变量,可能被其它线程访问到。
如果不存在逃逸行为,则可以对该对象进行如下优化:锁消除、标量替换和栈上分配。
- 栈上分配:将堆分配转化为栈分配。如果某个对象在子程序中被分配,并且指向该对象的指针永远不会逃逸,该对象就可以在分配在栈上,而不是在堆上。在有垃圾收集的语言中,这种优化可以降低垃圾收集器运行的频率。
- 锁消除:如果发现某个对象只能从一个线程可访问,那么在这个对象上的操作可以不需要同步。
- 标量替换:如果某个对象的访问方式不要求该对象是一个连续的内存结构,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。
逃逸分析在JVM使用编译模式的时候才启用。
JVM的执行模式有三种
解释模式、编译模式、混合模式。
解释模式
通过解释器将源代码逐条解释成机器语言,然后提交给计算机执行,解释一条执行一条,不形成目标程序,不依赖于平台。
如在终端上打一条命令或语句,解释程序就立即将此语句解释成一条或几条指令并提交硬件立即执行且将执行结果反映到终端,从终端把命令打入后,就能立即得到计算结果。这种工作方式很适合于人通过终端设备与计算机交互。
缺点:解析需要时间,不生成目标程序,而是一句一句的执行的方式会造成计算机资源的浪费,即执行效率低。
编译模式
先将所有的JVM字节码一次编译为机器码,然后一次性执行所有机器码。
由编译器将目标代码一次性全部编译成目标程序,再由机器运行目标程序。相比解释执行编译执行效率高,占用资源小,适合复杂程序。
编译过程是:先分析(词法分析和语法分析),后综合(优化代码,存储分配和目标代码生成),从而得到目标程序。为了完成这些分析综合任务,编译程序采用对源程序进行多次扫描的办法,每次扫描集中完成一项或几项任务,也有一项任务分散到几次扫描去完成的。编译的过程需要花费时间,编译后的机器码具有平台相关性,运行速度快。
缺点:兼容性差
混合模式
依然使用解释模式执行代码,但是对于一些热点代码采取编译模式执行,这些热点代码对应的机器码会被缓存起来,下次执行无需再编译。
JVM默认采用混合模式执行代码。
其实解释模式和编译模式很好区分,就是一个先全编译再执行,一个一边编译一边执行。
java的源代码首先通过javac编译器编译成字节码(bytecode),然后在运行时,通过JVM内嵌的解释器将字节码转换成最终的机器码,而机器码的数量比JVM字节码要多的多的多。
而其中的编译模式,就用到了JIT(Just In Time Compiler)即时编译技术,在即时编译过程中JVM可能会对我们的代码做一些优化,就比如对象逃逸分析等。