编译器优化 [2]- 方法内联

方法内联

当一个线程调用方法时,就会把栈帧压入到栈中。压栈和出栈都是有Cpu,内存,时间开销的。

Jvm会自动识别热点方法,并发起方法内联。

方法内联就是把目标方法的代码复制到发起调用的方法之中,避免发生真实的方法调用。可以避免压栈和出栈的操作。提高效率。

方法内联:

public class InlineTest {
    private static int add1(int x1,int x2,int x3,int x4){
        return add2(x1, x2) + add2(x3, x4);
    }

    private static int add2(int x1, int x2) {
        return x1 + x2;
    }

    //内联后
    private static int add(int x1,int x2,int x3,int x4){
        return x1+ x2 + x3+ x4;
    }

}

 方法内联的条件

  1. 方法体足够小

    • 热点方法:如果方法体小于325字节会尝试内联,可用-XX:FreqInlineSize修改大小
    • 非热点方法:如果方法体小于35字节会尝试内联,可用-XX:MaxInlineSize修改大小
  2. 被调用方法运行时的实现被可以唯一确定

    • static方法、private方法以及 final 方法,JIT可以唯一确定具体的实现代码
    • public 的实例方法,指向的实现可能时自身、父类、子类的代码(因为有多态的实现),当且仅当JIT能够唯一确定方法的具体实现时,才有可能完成内联

使用方法内联的注意点   

根据以上两个条件,可以总结出使用方法内联的注意点

  1. 尽量让方法体小一些,在方法体中不要编写大量的代码
  2. 尽量使用 final 、private、static  关键字修饰方法,避免因为多态,需要对方法做额外的检查。(还有可能在检查之后,发现不能确定方法唯一)
  3. 一些场景下,可通过Jvm参数修改阈值,从而让更多方法内联。

内联可能带来的问题

优化无非就是时间换空间,空间换时间。内联本质上是空间换时间。经过内联后方法的代码里会变多,在一些极端环境下,会造成

  • CodeCache 的溢出,导致JVm退化成解释执行模式。CodeCache 是热点代码测缓存区,即使编译器编译过的代码、以及本地代码,都会存放在CodeCache区。 JDK8里CodeCache默认是240M。

内联相关参数

 


 测试方法内联性能

循环执行方法查看性能

public class InlineTest {

    public static void main(String[] args) {
        Random random = new Random();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            int a = random.nextInt();
            int b = random.nextInt();
            int c = random.nextInt();
            int d = random.nextInt();
            add1(a,b,c,d);
        }
        long end = System.currentTimeMillis();
        System.out.println("执行花费了    " + (end - start)+"ms" );
    }


    private static int add1(int x1,int x2,int x3,int x4){
        return add2(x1, x2) + add2(x3, x4);
    }

    private static int add2(int x1, int x2) {
        return x1 + x2;
    }
}

加入Jvm参数  

-XX:+UnlockDiagnosticVMOptions  -XX:+PrintInlining

 执行方法查看控制台打印信息

可以看到打印出了方法大小 

 add1(12 bytes) 方法体的字节是12字节      ;  add2 (4 bytes)add2方法体大小是4字节

 inline  表示方法已经内联     

(hot) 表示是热点方法

 修改JVM参数阈值,使其不满足内联条件 

    -XX:FreqInlineSize=1  内联条件1字节

-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining -XX:FreqInlineSize=1

控制台打印如下:可以看到方法体大小超过了阈值,方法就没有内联。

正常情况下,编译器这块使用默认值就可以了,不需要区优化改动。因为现在Jvm已经非常智能,l非常强大了。一般来说可以忽略掉(编译器优化)这些细节,优化的工作交给JvM 来完成。

        但是当项目出现性能瓶颈的时候,要能想到可以做方法内联的优化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值