该测试的结论与第一个测试一样 —— final 关键字不会产生任何影响。我本以为该测试将证明 inlinableParentFinalMethod4 以无类型保护的方式进行内联,但结果表明事实并非如此。
多态性
最后,我们来看涉及多态分派(polymorphic dispatch)的测试结果。单态调用的性能开销与之前virtual方法相近。但对于双态与超多状态调用,由于需要在一张较大的虚拟表上面进行查找,所以需要更多的时间。而一旦我们开启内联支持,类型分析(type profiling )将会在单态或双态的调用点启用,使得在这些调用点上的方法调用的开销减少。但与层级结构的实例一样,这只会减少少量的时间。相比而言,超多状态的实例则依旧耗时较长。记住,我并没有说在这个测试中hotspot禁用了内联,它只是没有实现多态调用点的多态内联缓存。
我们从中学到了什么?我认为,需要我们引起注意的是,很多人没有认识到不同方式的方法调用所花费的时间是不一样的。即便有些人发现了这种问题,但他们不去证明是否真的如此。作为第一个吃螃蟹的人,我列出了各种坏的假设,因此我希望这份研究能够帮助到大家。以下是我很乐于与大家分享的一些结论:
最快与最短的方法调用的类型之间存在巨大的性能差别。
在实际应用中,添加或删除final关键字并不会真正影响性能。但如果除此以外,你还在层级结构上进行某些操作,那这些行为则可能导致性能下降。
更深的类的层次结构并不会真正影响到调用的性能。
单态调用比双态调用更快。
双态调用比超多状态调用更快。
我们在能够进行剖析(profile-ably),但是不能进行查验的单态调用点中看到类型保护,这种保护会使得这些调用点的调用性能低于那些能够进行查验的单态调用点。
我想说的是,对我而言,类型保护带来的性能开销是一个“重大发现”。这是一个我之前很少提及,并且总是当做无关事物忽视掉的因素。