• 编译器优化:方法内联


    方法内联的思想是,把目标方法的代码复制代发起调用的方法之中,避免发生真实的方法调用。

    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;
        }
    }
    

    如上代码,我们知道线程执行方法时,会向虚拟机栈压入栈帧,add1方法中调用了两次add2方法会压入两次add2的栈帧。频繁出入栈操作,消耗内存和时间。

    JVM可以对上面的操作进行方法内联优化,优化为下面代码。

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

    方法内联的条件有两个:

    1. 方法体足够小。

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

      1. static、private、final方法,JIT可以唯一确认具体的实现代码。
      2. public实例方法,指向的实现可能是自身、父类、子类的代码(多态),只有当JIT唯一确认方法实现时,才有可能内联。

    内联可能带来的问题:会导致方法变大,使得CodeCache溢出,导致JVM退化成解释执行模式。

    一般情况,使用默认JVM参数就好。

    测试方法内联

    @Slf4j
    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 long compute() {
            long start = System.currentTimeMillis();
            int result = 0;
            Random random = new Random();
            for (int i = 0; i < 10000000; i++) {
                result = add1(random.nextInt(), random.nextInt(), random.nextInt(), random.nextInt());
            }
            long end = System.currentTimeMillis();
            return end - start;
        }
    
        public static void main(String[] args) {
            long compute = compute();
            log.info("花费{}ms", compute);
        }
    }
    
    花费362ms
    花费483ms
    

    设置JVM参数,打印内联日志,开关内联(通过设置内联阈值)。

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

    默认开启方法内联,比直接关掉运行更快。

    JVM参数备注

    image

    版权声明:本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    线程
    实数四则运算表达式的计算,C++ 实现
    [Compiling Principles] LEX基本功能的实现
    2010年ImagineCup,我们共同走过
    [WPF] Felix 的线程学习笔记(一)——从Win32的消息循环说起
    [WPF] Felix 的线程学习笔记(二)——从WPF入手,实现简单的多线程
    [ASP] asp 中的ajax使用
    银行家算法C++实现
    [ASP.NET] 事件与委托的处理
    小郁闷
  • 原文地址:https://www.cnblogs.com/dtyy/p/15733449.html
Copyright © 2020-2023  润新知