[英]Does it matter for runtime performance if a method is called by its explicit type?
我目前正在编写一个创建Java字节代码并编写方法调用的应用程序。 到目前为止,编写此字节代码的模块没有关于调用方法调用的实例的实际类型的信息,但它确实知道为其定义特定方法的类型。 例如:
class Foo {
public void foo() { }
}
class Bar extends Foo {
public void bar() { }
}
当前版本的引擎将执行
INVOKEVIRTUAL Foo.foo
甚至在Bar
类型的对象上,因为它知道foo
是在Foo
中定义的。 这在JVM中是合法的(当然),但Java编译器会将其转换为
INVOKEVIRTUAL Bar.foo
当它是“正常”的Java源代码时。 我目前想知道JVM是否实际使用了显式子类型的信息,或者在加载类时是否忽略/优化了它。 我想知道,因为验证程序正在计算实际的类型,并且不会让我编写非法的方法调用,我想知道为什么运行时在它已经可用时不会使用这些信息。 我特别想知道当超类型是接口( INVOKEINTERFACE
)时它是否会对性能产生影响,如果JVM无法确定实际类型,则无法使用虚方法表。
我当然可以扩展我的模块,但我需要提供额外的信息,这会使我的代码膨胀,如果它没有效果我不想做。 所以我问:类型会影响性能还是JVM会处理这种明确的解决方案?
字节码中的区别对于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.
您只能将invokespecial
用于当前类或其祖先的方法,这实际上是由Java虚拟机规范§4.9.2指定的 :
每个
invokespecial
指令必须命名实例初始化方法(第2.9节),当前类中的方法或当前类的超类中的方法。
invokeinterface
被称为是慢invokevirtual
/ invokestatic
,尤其是当它涉及到所谓的“megamorphic来电”:其中一个方法有很多种实现方式,而JIT编译器有没有办法来优化。 所以,明智的做法是宁可invokevirtual
到invokeinterface
。 并且您提到的类型越具体,乐观优化就越可能(我们认为这个方法是最终的,直到覆盖它的类被加载)才会起作用。
此处提供了更多信息: http : //java.dzone.com/articles/invoke-interface-optimisations
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.