Java 为什么JVM中没有提示JIT编译器的基础结构?

Java 为什么JVM中没有提示JIT编译器的基础结构?,java,jvm,jit,Java,Jvm,Jit,我在回顾一个涉及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++) {

我在回顾一个涉及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);
    }
}
公共静态整数倍增two(整数x){
返回x*2;
}
公共静态void入口点(){
整数和=0;
对于(int i=0;i<10_000;i++){
//由于某些任意原因,multiplyByTwo无法内联
总和+=乘以2(i);
}
}
作为一名程序员,我可能知道有一个编译器不知道的优化领域。例如,如果
multiplyByTwo
将被强制内联,则可能存在大量优化,但由于各种限制(例如方法大小或内联深度),可能会从内联中忽略。为什么没有办法告诉编译器“嘿,我很确定你应该更喜欢内联该方法而不是它”?我肯定我不是第一个想到这一点的人,有人讨论过没有实现这样的功能——为什么

p、 请注意,我说的是提示而不是指令;我知道后一种选择弊大于利。

好吧,JVM的优化器得到的提示是,这种方法是内联的一个很好的候选方法:

  • 它是
    静态的
    私有的
    ,即不可重写
  • 非常短
  • 它在一个循环中被调用了好几次
事实上,您认为此方法是一个好的候选方法是基于相同的技术证据,因此添加一个您认为这是一个好的内联候选方法的提示不会添加任何新信息,只会添加冗余

因此,如果JVM仍然没有内联该方法,无论出于何种原因,尽管所有这些技术属性都支持内联,没有理由假设一个非强制性的、非技术性的提示(很可能来自相同的技术属性)会改变JVM的决定

您可以选择任何您想要的潜在原因、针对某些问题的保护、过于严格的限制,甚至是有缺陷的JVM实现,在任何一种情况下,您都会看到同样的原因也适用于有您的提示的方法,即使它被证明是没有根据的原因,因为这也适用于没有您的提示的方法。因此,在后一种情况下,显而易见的解决方案是修复JVM中的缺陷,而不是添加一般的提示机制

一般的暗示机制尤其值得怀疑,因为代码应该是独立于平台的。如果您使用特定的JVM实现查看已知环境中的特定运行,情况会有所不同。例如,HotSpot支持
-XX:CompileCommand
选项。所以在你的情况下,你可以使用
-XX:CompileCommand=inline,您的/class/Name,multiplyByTwo
试图说服JVM内联该方法。当然,正确的拼写很重要。在您的问题中,该方法曾经被命名为
multipleByTwo
,然后
multipleByTwo

事实上,有一个基础结构来控制HotSpot JVM编译器

1.编译器命令文件 您可以使用
-XX:compileCommand=
JVM选项指定包含编译器命令的文件。有强制内联、从编译中排除方法、设置每个方法选项(例如,
MaxNodeLimit
)等命令。可以找到可用命令的完整列表

示例编译器命令文件可能如下所示

inline java.util.ArrayList::add
exclude *::<clinit>
print com.example.MyClass::*
内联java.util.ArrayList::add 排除*:: 打印com.example.MyClass::* 2.注释 JDK特定注释是控制JVM优化的另一种方法。HotSpot JVM知道某些注释,例如


注意:所有这些机制都是非标准的。它们仅适用于OpenJDK和Oracle JDK。没有标准的方法来提示JVM编译器,因为有许多JVM实现具有完全不同的编译策略。特别是,有些JVM根本没有JIT编译。

确定何时以及如何通过JIT优化运行时的AI算法(如方法内联)非常难掌握。但使方法“final”可以提示java将其内联。好吧,没有任何方法可以告诉JIT确定方法是内联的。如果最大内联深度更大,这个问题可能会消失——问题就是这样;或者,为什么不能使用JVM参数来增加深度呢。更一般地说,问题是“为什么JIT在Y时停止进行X优化”:因为JIT的作者不能花费无限的时间来确保每个可能的情况都得到处理。它在大多数情况下都能很好地工作。@vvtx是的,我知道我不能口述编译器(至少在现代jvm中是这样)。我的问题是“为什么没有人实现它?”而不是“如何强制编译器按照我的意愿内联?”@AndyTurner是的,我知道最大内联深度。但开发人员可能会提示编译器,如果他确信这样做将有利于整体性能,那么它应该更深入地内联一个方法,而不是从顶部内联(保持指定的深度)。整个问题不是关于内联本身,它只是展示了一个示例,其中开发人员入侵可能会带来性能好处,但是,由于未知原因,入侵是不可能的——我想知道这个原因。我的评论不是关于内联本身。它指出,JIT尝试优化的价值必然存在实际的局限性,而且它在绝大多数情况下都能很好地工作,这一事实消除了暗示机制的额外复杂性。我知道内联规则(顺便说一句,我听过很多次)