如果方法是通过其显式类型调用的,那么运行时性能是否重要?

Raf*_*ter 10 java jvm bytecode

我目前正在编写一个创建Java字节代码并编写方法调用的应用程序.到目前为止,编写此字节代码的模块没有关于调用方法调用的实例的实际类型的信息,但它确实知道为其定义特定方法的类型.例如:

class Foo {   
  public void foo() { } 
}

class Bar extends Foo {   
  public void bar() { } 
}
Run Code Online (Sandbox Code Playgroud)

当前版本的引擎将执行

INVOKEVIRTUAL Foo.foo
Run Code Online (Sandbox Code Playgroud)

甚至在类型的对象上,Bar因为它知道在foo中定义了Foo.这在JVM中是合法的(当然),但Java编译器会将其转换为

INVOKEVIRTUAL Bar.foo
Run Code Online (Sandbox Code Playgroud)

当它是"正常"的Java源代码时.我目前想知道JVM是否实际使用了显式子类型的信息,或者在加载类时是否忽略/优化了它.我想知道,因为验证程序正在计算实际的类型,并且不会让我编写非法的方法调用,我想知道为什么运行时在它已经可用时不会使用这些信息.我特别想知道当超类型是interfaces(INVOKEINTERFACE)时它是否会对性能产生影响,如果JVM无法确定实际类型,则无法使用虚方法表.

我当然可以扩展我的模块,但我需要提供额外的信息,这会使我的代码膨胀,如果它没有效果我不想做.所以我问:类型会影响性能还是JVM会处理这种明确的解决方案?

Mar*_*nik 7

字节码中的区别对于JIT编译代码的性能都不重要.

HotSpot会定期为每个invokevirtual呼叫站点保留一个类型配置文件.如果记录表明只调度了一种类型,JIT编译器会将其视为一个invokespecial调用,基本上是直接跳转到被调用者,甚至内联被调用者.

以上描述了最难的情况的优化,一种完全通用的虚拟方法.HotSpot还知道哪些方法是有效的最终方法:在加载类的集合中,不会出现对该方法的覆盖.在这种情况下,HotSpot继续类似于上面的操作,但省略了一些指令(执行类型断言的指令).

我还在努力破解.class文件,以便invokevirtual替换为invokespecial.结果是VerifyError:

Exception in thread "main" java.lang.VerifyError: 
Bad invokespecial instruction: current class isn't assignable to reference class.
Run Code Online (Sandbox Code Playgroud)

您只能使用invokespecial当前类或其祖先的方法,这实际上是由Java虚拟机规范§4.9.2指定的:

每条invokespecial指令都必须命名实例初始化方法(第2.9节),当前类中的方法或当前类的超类中的方法.


And*_*lav 5

invokeinterface众所周知,它比invokevirtual/慢invokestatic,特别是当涉及到所谓的“超态调用”时:其中一个方法有很多实现,而 JIT 编译器无法优化。invokevirtual所以选择是明智的invokeinterface。您提到的类型越具体,乐观优化(我们认为此方法是最终方法,直到加载覆盖它的类)就越有可能起作用。

此处提供了更多信息: http: //java.dzone.com/articles/invoke-interface-optimizess