后端编译与优化

后端编译与优化

即时编译器

  • hotspot有一个解释器与C1(客户端编译器)、C2(服务端编译器)两个即时编译器,采用分层工作方式:

    0:纯解释执行

    1:使用C1编译,进行简单可靠的优化,不开性能监控。

    2:同上,但开启方法、回边次数统计等有限性能监控。

    3:同上,但开启全功能性能监控。

    4:使用C2编译,更多优化,更激进优化。

  • 开启分层后,热点代码可被多次编译

  • 热点代码触发条件:被多次调用的方法、多次执行的循环体。但两种情况编译目标都是整个方法体。这里多次的判定条件是:1.采样法,经常查看栈顶,看看谁老是被调用。2.计数法,为每个方法维护计数器。Hotspot使用第二种方式。

    方法计数器与回边计数器(循环体循环次数计数器)调用次数的和与一个阈值进行比较,改进:计数器的计数有衰减。

提前编译器

  • 即时编译器的最大缺点就是要占用程序执行的时间进行编译,提前编译器有两条路,一条是像C++一样进行正统的编译,另一条是将即时编译器的工作提前完成,它的优劣得失:

    优点:节约了程序运行时间。

    缺点:相比即时编译器不能进行性能分析优化、不能进行激进预测性优化、及不能进行链接时优化(像C++那种就是动态链接的代码跟主体代码隔阂很大,不能进行统一优化)

后端编译优化

  • 方法内联

    其是其他优化方法的基础,但是由于java本身的方法解析与分派方式导致很多虚方法无法提前定位具体方法版本,因此多数情况下方法内联都是一种激进优化。

  • 逃逸分析

    就是判断某些变量的作用域,看看某个变量是否会作为形参被传递或者被其他线程引用。

    如果判断对象不会逃逸有三种优化方式:

    栈上分配:既然作用域就在本方法或者本地,那对象不在堆中而在栈中分配。

    标量替换:不会创建一个对象,而是将对象的字段按照基本类型进行替换。

    同步消除:变量不会被其他线程引用,关于这个变量的同步动作就可以消除。

  • 公共子表达式消除

    如果表达式已经被算过了,且组成表达式的变量都没变化,那就直接存储一个表达式的值。

  • 数组边界检查消除

    就是省略一次次的边界检查,确定下标不会越界时就去掉边界检查,包括很多检查都可以省略,甚至只编译try语句中的内容,当真的进入catch中时再真正执行。

你可能感兴趣的:(jvm)