分层编译和逃逸分析在1.8中是默认是开启的;
即时编译(Just-in-time Compilation,JIT)是一种通过在运行时将字节码翻译为机器码,从而改善字节码编译语言性能的技术。在HotSpot实现中有多种选择:C1、C2和C1+C2,分别对应client、server和分层编译。
1、C1编译速度快,优化方式比较保守;
2、C2编译速度慢,优化方式比较激进;
3、C1+C2在开始阶段采用C1编译,当代码运行到一定热度之后采用G2重新编译;
编译阈值:
编译优化只有在代码执行足够次数才会进行优化,在执行的过程中不断收集各种数据作为优化决策;所以在优化完成之前,User还是在堆中分配的;
-XX:CompileThreshold 进行阈值的设定;
除了标准编译还有一种叫做OSR(On Stack Replacement)栈上替换的编译,对方法中循环执行的代码进行优化,也需要一个阈值;
-XX:CompileThreshold = 10000 触发编译优化阈值
-XX:OnStackReplacePercentage = 140 栈上替换百分比
-XX:InterpreterProfilePercentage = 33 编译内容百分比
OSR trigger = (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100 = 10700
JIT编译在默认情况是异步进行的,当触发某方法或某代码块的优化时,先将其放入编译队列,然后由编译线程进行编译,编译之后的代码放在CodeCache中,CodeCache的大小也是有限的,CompileThreshold设置的太低,JIT会将一大堆执行不那么频繁的代码进行编译,并放入CodeCache,导致之后真正执行频繁的代码没有足够的空间存放。
逃逸分析:通过动态分析对象的作用域,为其他优化手段如栈上分配、标量替换和同步消除等提供依据,发生逃逸行为的情况有:
方法逃逸:一个对象在方法中定义之后,作为参数传递;
线程逃逸:类变量或实例变量可能被其他线程访问到;
同步消除:如果确定对象不会发生线程问题,即使添加了同步也会被消除,默认是开启的,参数是-XX:=EliminateLocks;
标量替换:标量是不可分割的量,可以继续分解的叫聚合量;
如果发现一个对象不会被外部访问并且该对象可以被拆散,那么经过优化之后,并不直接生成对象,而是在栈上创建成员变量;
-XX:+EliminateAllocations可以开启标量替换, -XX:+PrintEliminateAllocations查看标量替换情况。
栈上分配:理论上的概念是在栈上分配对象,但是现在是通过标量替换的方法实现的;