如何说服JVM内联接口方法?

akb*_*ram 2 java optimization jvm compiler-optimization

我有一个以接口为根的类层次结构,并使用抽象基类实现.它看起来像这样:

interface Shape {
  boolean checkFlag();
}

abstract class AbstractShape implements Shape {
  private boolean flag = false;

  protected AbstractShape() { /* compute flag value */ }

  public final boolean checkFlag() { return flag; }
}

interface HasSides extends Shape { 
  int numberOfSides();
}

interface HasFiniteArea extends Shape { 
  double area();
}

class Square extends AbstractShape implements HasSides, HasFiniteArea {

} 

class Circle extends AbstractShape implements HasFiniteArea { 
}

/** etc **/
Run Code Online (Sandbox Code Playgroud)

当我使用VisualVM对正在运行的代码进行采样时,似乎AbstractShape.checkFlag()从不内联并占用了总程序运行时间的14%,这对于一个简单的方法来说是个淫秽,即使对于一个经常调用的方法也是如此.

我在基类上标记了方法final,并且(当前)实现"Shape"接口的所有类都扩展了AbstractShape.

我能正确解释VisualVM样本结果吗?有没有办法说服JVM内联这个方法,还是我需要撕掉接口并使用抽象基类?(我不愿意,因为层次结构包括像HasFiniteArea和HasSides这样的接口,这意味着层次结构没有完美的树形式)

编辑:要清楚,这是一种在任何宇宙中都应该内联的方法.在2分钟执行期间,它被称为超过4.2亿次,因为它没有内联并且仍然是虚拟调用,它占运行时的14%.我问的问题是什么阻止JVM内联这个方法,我该如何解决?

Ole*_*liv 5

这是维基百科的引用

一个常见的误解是,声明一个类或方法final可以通过允许编译器在任何调用它的地方直接插入方法来提高效率.这不完全正确; 编译器无法执行此操作,因为类在运行时加载,并且可能与刚刚编译的版本不同.此外,运行时环境和JIT编译器具有关于已经加载了哪些类的信息,并且能够更好地决定何时内联,该方法是否是最终的.

另见本文.