首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >超级虚拟调用--试图优化它

超级虚拟调用--试图优化它
EN

Stack Overflow用户
提问于 2022-02-05 11:24:21
回答 1查看 142关注 0票数 1

我们知道,有些技术在JVM中使虚拟调用不太昂贵,比如内联缓存或多态内联缓存。

让我们考虑以下情况:

Base是一个接口。

代码语言:javascript
复制
public void f(Base[] b) {
    for(int i = 0; i < b.length; i++) {
          b[i].m();   
    }
}

我从我的分析器中看到,调用虚拟(接口)方法m是相对昂贵的。f在热门路径上,它被编译成机器代码(C2),但是我看到对m的调用是一个真正的虚拟调用。这意味着JVM没有对其进行优化。

问题是,如何处理这种情况?显然,我不能让方法m在这里不是虚拟的,因为它需要经过认真的重新设计。

我能做什么吗?或者我必须接受它?我在想如何“强迫”或“说服”JVM

  1. 在这里使用多态内联缓存-- b`中不同类型的数量相当低--介于4-5个类型之间。
  2. 用于展开这个循环长度的b也相对较小。展开后,内联缓存在这里可能会有所帮助。

事先谢谢您的建议。致以敬意,

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-02-05 13:46:31

HotSpot JVM最多可以对一个虚拟调用的两个不同目标进行内联,对于更多的接收者,将通过vtable/itable 1进行调用。

为了强制更多接收者的内联,您可以尝试手动地去虚拟化调用。

代码语言:javascript
复制
if (b.getClass() == X.class) {
    ((X) b).m();
} else if (b.getClass() == Y.class) {
    ((Y) b).m();
} ...

在执行配置代码期间(在解释器或C1中),JVM收集每个呼叫站点的接收方类型统计信息。然后在优化编译器(C2)中使用此统计信息。在您的示例中只有一个调用站点,因此统计数据将在整个执行过程中进行聚合。

但是,例如,如果b[0]总是只有两个接收方( XY ),而b[1]总是有另外两个接收方( ZW ),JIT编译器可能会受益于将代码拆分为多个调用站点,即手动展开:

代码语言:javascript
复制
int len = b.length;
if (len > 0) b[0].m();
if (len > 1) b[1].m();
if (len > 2) b[2].m();
...

这将拆分类型配置文件,以便可以单独优化b[0].m()b[1].m()

这些都是依赖于特定JVM实现的低级技巧。通常,我不推荐它们用于生产代码,因为这些优化是脆弱的,但它们肯定会使源代码更难阅读。毕竟,大变形电话也没那么糟糕。

1

2

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70997550

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档