Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JVM JIT能否在子类中专门化非重写方法?_Java_Performance_Inheritance_Optimization_Jvm - Fatal编程技术网

Java JVM JIT能否在子类中专门化非重写方法?

Java JVM JIT能否在子类中专门化非重写方法?,java,performance,inheritance,optimization,jvm,Java,Performance,Inheritance,Optimization,Jvm,好吧,这个标题无法让人理解,但基本上我的意思是,给定类Base中的某个方法m(),该方法在某些派生的子类中未被重写,那么当前JVM1中的JIT编译器是否能够“专门化”0m(),或者继承和不重写Base.m()的派生成员是否会共享相同的编译代码 这种专门化是有意义的,因为派生类定义了一些使m()更简单的东西。例如,为了便于讨论,假设m()调用另一个成员函数n(),并且在派生类中定义了n(),这样当n()内联到m()中时,后者就大大简化了 具体地,考虑下面类中的两种非抽象方法(它们都是())/代码>

好吧,这个标题无法让人理解,但基本上我的意思是,给定类
Base
中的某个方法
m()
,该方法在某些派生的子类
中未被重写,那么当前JVM1中的JIT编译器是否能够“专门化”0
m()
,或者继承和不重写
Base.m()
的派生成员是否会共享相同的编译代码

这种专门化是有意义的,因为派生类定义了一些使
m()
更简单的东西。例如,为了便于讨论,假设
m()
调用另一个成员函数
n()
,并且在派生类中定义了
n()
,这样当
n()
内联到
m()
中时,后者就大大简化了

具体地,考虑下面类中的两种非抽象方法(它们都是<代码>())/代码>类型的方法,而抽象方法是对应的<代码>()(<代码>方法):

两者都依赖抽象的方法。假设您现在有一个派生的
,如下所示:

public class Derived extends Base {

  final int divisor() {
    return 2;
  }

  final boolean isSomethingEnabled() {
    return false;
  }
}
现在,
divide()
doSomething()
方法的有效行为非常简单,
divide
不是被任意数字整除,而是可以通过位操作完成的简单减半。
doSomething()
方法始终返回false。我假设当
JIT
转到compile
divide()
doSomething()
时,如果
Derived
是唯一的子类,那么一切都是好的:两个抽象调用(当前)只存在一个可能的实现,CHA将启动并内联唯一可能的实现,一切都是好的

但是,在存在其他派生类的更一般的情况下,我不清楚JVM是否只会在
Base
中编译一个2版本的方法,并调用
invokevirtual
抽象方法,或者它是否足够聪明地说,“嘿,即使派生没有覆盖
除数()
我应该专门为它编译一个版本,因为它会更简单”

当然,即使没有专门的重新编译,积极的内联通常也会使它工作得很好(例如,当您调用
divide()时)
对于一个已知的类,甚至很可能是一个派生的类,不管怎样,内联很可能为您提供良好的实现,但是,同样,在很多情况下,这样的内联都没有完成


0我的专门化我指的不是任何特定的东西,除了编译适用于某个受限域的函数的另一个版本,在相同的意义上说,内联是对特定调用站点的专门化形式,或者以相同的方式,大多数函数在某种程度上专门化到当前上下文(例如,加载的类、关于空值的假设等)

1特别是,当一个人说“JVM可以胡说八道吗?”时,他通常是在谈论热点,我也主要是在热点,但还有其他JVM是否也可以这样做


2当然,您可能有多个版本的函数,用于堆栈上的替换、不同的编译器级别、发生去优化时等等。

不,我的理解是,如果JVM在概要文件优化过程中发现除数()通常归结为某种方法

您是否尝试从诊断打印以查看发生了什么

与其猜测JIT在做什么,不如看一眼 在打开java命令行标志时发生了什么: -XX:+PrintCompilation-XX:+UnlockDiagnosticVMOptions-XX:+PrintInLine(来自)


JVM既不定义也不重新定义类型。它解释行为的运行实现。它是编译器,即处理类型的源语言。JVM是低级的“金属”类型及其实例是创建一系列受输入影响的可观察事件的指令。随着时间的推移,这一系列输入和可观察事件构成了计算机科学家所谓的程序“语义”

JVM需要找出执行这些指令的方法,同时保留语义。有时,它实际上会完全破坏类结构。从概念上讲,类实例存在于具有标记属性的堆内存中。在一段时间内,直到语义由于某些状态更改而禁止它,JVM可能会在寄存器中,甚至在RAM中,eep两个活动值,并忽略定义类的其余部分。这是“专门化”方法吗

不,不是。JVM中没有新的定义,没有新的Java级指令集,也没有短暂的类型。目前只有一种临时的、编译的和优化的方式来实现指令。当优化不再有效,或者同样重要时,JVM甚至会恢复到解释字节码。字节码将不包含任何new类型也是。它是一种汇编语言,重新定义高级代码的要求高于其工资等级

总之,程序中唯一的类型是源代码中强制使用的类型,而不是字节码或JVM。所有语义都来自源代码。

根据:

  • 方法通常是内联的。这增加了编译器的优化“视野”
  • 静态、私有、最终和/或“特殊”调用很容易内联
  • 如果类层次结构允许,虚拟(和接口)调用通常会降级为“特殊”调用。如果进一步的类加载会破坏,则会注册依赖项
  • 带有不平衡类型配置文件的虚拟(和接口)调用是通过乐观检查编译的,以支持历史上常见的类型
    public class Derived extends Base {
    
      final int divisor() {
        return 2;
      }
    
      final boolean isSomethingEnabled() {
        return false;
      }
    }
    
        if (this.getClass() != Derived.class) {
            uncommon_trap();  // this causes deoptimization
        }
        return false;