我正在审查一个触及JIT内联语义的会议演示文稿,其中作者固定了奇怪的行为(当然,只有第一眼看上去很奇怪) - C2比C1慢,因为由于内嵌深度过大而无法内联方法。它可以在以下示例中表示:
public static int multipleByTwo(int x) {
return x * 2;
}
public static void entrypoint() {
int sum = 0;
for (int i = 0; i < 10_000_000; i++) {
// due to some arbitrary cause, multiplyByTwo doesn't get inlined
sum += multiplyByTwo(i);
}
}
作为一名程序员,我可能知道编译器不知道有一个优化领域。例如。如果强制内联multiplyByTwo
,则可以进行大量优化,但由于各种约束(例如方法大小或内联深度),可以从内联中省略。为什么没有办法告诉编译器“嘿,我很确定你应该更喜欢内联那个方法而不是”?我敢肯定,我不是第一个考虑这个问题的人,并且讨论导致没有实现这样的功能 - 为什么?
P.S。请注意,我正在谈论提示而不是指令;我确实理解后一种选择会带来更多的伤害而不是利益。
答案 0 :(得分:7)
事实上,有基础设施来控制HotSpot JVM编译器。
您可以使用-XX:CompileCommandFile=
JVM选项指定包含编译器命令的文件。有强制内联,从编译中排除方法,设置每个方法选项(例如MaxNodeLimit
)等命令。可以找到可用命令的完整列表here。
示例编译器命令文件可能类似于
inline java.util.ArrayList::add
exclude *::<clinit>
print com.example.MyClass::*
JDK特定的注释是控制JVM优化的另一种方法。 HotSpot JVM知道某些注释,例如
@java.lang.invoke.ForceInline
@java.lang.invoke.DontInline
@java.lang.invoke.Stable
@sun.misc.Contended
注意:所有这些机制都是非标准的。它们仅适用于OpenJDK和Oracle JDK。没有标准的方法来提示JVM编译器,因为有许多JVM实现具有完全不同的编译策略。特别是,JVM根本没有JIT编译。
答案 1 :(得分:2)
嗯, 提示JVM的优化器,这个方法适合内联:
static
或private
,即不可覆盖的事实上,你假设这种方法是一个很好的候选人是基于相同的技术证据,所以添加一个你认为这是一个好的内联候选人的提示不会添加任何新的信息,只有冗余。
因此,如果JVM仍然没有内联该方法,无论出于何种原因,尽管所有这些技术属性都在内联,但没有理由假设非强制性的非技术性提示,很可能源于相同的技术属性将决定JVM的决定。
你可以选择任何你想要的潜在理由,防范某些问题,限制性太强,甚至是有缺陷的JVM实现,在任何一种情况下,你都会看到同样的理由同样适用于你的提示方法,甚至如果事实证明这是一个没有根据的理由,因为这也适用于没有你提示的方法。所以在后一种情况下,明显的解决方案是修复JVM中的缺陷,而不是添加一般的提示机制。
一般的提示机制特别值得怀疑,因为代码应该是平台无关的。如果您在具有特定JVM实现的已知环境中查看特定运行,则情况会有所不同。例如。 HotSpot支持-XX:CompileCommand
选项。所以在你的情况下,你可以使用
-XX:CompileCommand=inline,your/class/Name,multiplyByTwo
试图说服JVM内联该方法。当然,正确的拼写很重要。在您的问题中,该方法曾被命名为multipleByTwo
,然后是multiplyByTwo
...