我在jitwatch中为一段代码运行的基准测试中分析了热点日志,发现很多方法调用由于“无静态绑定”而没有内联。这些似乎只在调用默认接口方法时发生。
我的问题是默认接口方法是否阻止jit编译器内联它们的调用?
interface A {
default double a() {
return Math.random();
}
}
interface B extends A {
default double b() {
return a();
}
}
class C implements B {
public double c() {
double c = 0;
for (int i = 0; i < 1_000_000; ++i) {
c += b();
}
return c;
}
public static void main(String[] args) {
System.out.println(new C().c());
}
}
在jitwatch中进一步检查后,这个问题似乎与调用其他默认接口方法的默认接口方法有关。考虑到“无静态绑定”消息,这将更有意义。
2条答案
按热度按时间jdgnovmf1#
eugene的例子显示默认方法可以内联。
事实上,我认为内联的标准应该与任何其他非静态方法相同。
要内联的代码的大小必须小于可调阈值。
该方法不能被类或接口的任何(当前加载的)子类中的方法重写。
在您的示例中,我认为内联应该是可能的,假设这是示例中涉及的所有代码。
但是,这里使用的特定jit可能有其他限制。例如,一个调用另一个默认方法的默认方法可能是一个边缘情况,这种情况非常罕见,不值得支持。另一种可能的解释是c1编译器没有进行深入的单态分派分析/优化。
另一方面,这可能是过早的优化。。。除非您的性能评测已经在代码中确定了一个特定的热点,在那里内联可能会产生显著的影响。通常情况下,最好的策略是让编译器处理这个问题。如果您对代码进行微优化,以便为给定的java版本提供最佳性能,那么当您更改到较新的版本时,很有可能需要重做这项工作。
wooyq4lh2#
它是内联的。举个例子:
运行时使用:
看到一行有:
至于“无静态绑定”,它在这里出现,请注意,这是在
C1
. 因为调用方法myRandom
编译invokeInterface
(您可以在上面查看方法的类型C1
将内联),C1 compiler
不会内联它(据我所知的代码),但C2
威尔。