首页 > 解决方案 > java接口方法内联

问题描述

我对来自 c++ 世界的 java 很陌生。我正在运行一些服务器代码,该代码运行一个方法 foo() ,该方法每秒被调用几百万次。这是对延迟敏感的代码,并且该方法在分析器中也显示为消耗进程总 CPU 使用量的 20%。

int foo_old() {
     if (Float.isNan(this.x)) { // shows up in profiling
        res = do some computation; // some floating point comparison, doesn't show up in profiling;
        return res;
     } else {
        // Happens 99% of the time;
        res = do something else; // some floating point comparison, doesn't show up in profiling;
        return res;
     }
}

有没有一种简单的方法可以测试我的方法 foo 是否会被内联?我可以从正在运行的服务器中的探查器堆栈跟踪信息中知道吗?

我通过尝试简化方法 foo() 尝试了一些优化。基本上在 foo 中有一个 float.isNan 检查,它也显示在 profiler 上,惊讶地发现 nan 检查速度较慢。相比其他一些布尔运算(小于、大于浮点比较)更快。

我尝试的一种方法是删除 nan check ,即因为我在编译时知道一个对象是否需要 nan check ,所以我尝试存储一个功能接口(成员变量)并分配这个功能接口 foo_old (具有 nan check)或 foo_optimized (不做nan检查)基于创建对象时已知的对象属性(在对象的构造函数中,我为此接口分配了正确的方法引用。

class A {
  final FuncIf test; // Functional interface with same signature as foo_old, foo_new

  public A(bool optimize) {
      test = optimize ? this::foo_optimized : this::foo_old;
  }

  // same as the original foo mentioned above
  int foo_old() {
    ...
   }

  // No nan check
  int foo_optimized() {
        res = do some computation; 
        return res;
  }
}

现在,当我创建对象时,我知道在编译时间/对象构造时间使用哪个版本的 foo。所以我将接口变量分配给正确版本的 foo。部署后,我观察到延迟实际上增加了 < 10% 。尽管现在许多对象实际上将使用 foo 的优化版本。

是因为 foo 之前是直接方法调用,并且一旦我使用接口引用,调度虚拟 foo 的额外间接是我在延迟中看到的开销(接口方法调用的开销远大于 Nan 检查本身?? ) ? jvm编译器不能内联这个接口方法吗?

标签: javaperformanceinterfaceprofilingvirtual-functions

解决方案


唯一有根据的猜测是测量它的bytecode. 为此使用javap。基本上JVM有两个编译器C1C2; 两者都可以内联该方法。

JVM内联时关心三个参数(嗯,这些是我知道的,我也知道还有很多):

-XX:MaxInlineSize (35 by default)
-XX:FreqInlineSize (325 by default)
-XX:MinInliningThreshold (250 by default)

如果你的方法调用小于MinInliningThreshold(250),它遵守MaxInlineSize规则,这意味着如果它小于 35 字节,它将被内联。如果它被调用的更多,那么它会服从FreqInlineSize325 个字节(更多)。

您还可以做的是通过一些参数打印内联或不内联的内容:

-XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining

作为运行的结果,您可以看到如下消息:

  callee is too large

这是由打印的C1,它告诉您MaxInlineSize该编译方法的超出范围。或者:

  too big

超出C2时由编译器打印。MaxInlineSize或者 :

  hot method too big

C2超过时打印FreqInlineSize


推荐阅读