java - 可见性和 javac/JVM 内联

标签 java jvm javac jit inlining

方法/字段可见性对 Java 中的方法内联有何影响?

我想到的情况类似于 private 字段的 public getter:

private Thing blah;

public Thing getBlah() {
    return blah;
}

这里出现了几个问题。

首先,Java 编译器本身是否会进行内联?这个问题似乎有不同的答案,有些人说 yes有人说no 。我不知道这是因为它以前不做任何内联,但现在做了,还是只是有些人是对的,有些人是错的......

现在,如果它确实做了一些内联,我认为它不可能内联 getBlah() 调用是正确的吗?它们显然是内联有用的地方,因为该方法非常简单,并且调用方法的开销与方法本身的代码一样大。但如果它被编译器内联,您最终会得到直接访问 private 字段的字节码;那么 JVM 肯定会提示吗? (即使此方法是static final,这也适用。)

其次,JIT 编译器怎么样?据我所知,当涉及到该级别的内联时,这个问题并不适用。一旦生成 native 代码,JVM 就已经完成了检查,并确认我可以调用该方法(因为它是 public);这样它就可以生成内联调用的 native 代码,而不会出现任何可见性问题...是吗?

最佳答案

javac 编译器(以及任何有效的 java 编译器)不会也不可能内联 getters;想一想:您可以从该类扩展一个类并覆盖 getter。是的,如果编译器过度热心地内联该访问,它将无法通过验证程序(至少它不应该通过验证程序,但它们不会验证所有内容 - 在 java 1.3 中,您甚至可以使 main () 私有(private),它仍然可以工作...同样,javac 中曾经有一个 -O 选项,确实有时会搞砸你的代码)。

JIT 完全是另外一头野兽;它随时知道(至少现在是这样)是否存在方法的覆盖。即使稍后加载一个覆盖 getter 的类,它也可以对已经 JIT 的方法进行去优化,以反射(reflect)继承树上的更改(这是 AOT 编译器缺乏信息的优化之一)。 p>

因此它可以安全地内联任何它想要的内容。它也不需要人为地维护访问修饰符,因为编译后的机器代码中没有这样的东西,并且它再次知道什么是有效的代码转换(并且由于 getter 如此常见,因此对于 JIT 来说,它也是一个容易实现的目标)优化)。

编辑:为了绝对清楚,上面的段落讨论了潜在的虚拟方法;特别是那些不是私有(private)的、静态的或最终的。 Javac 在某些情况下可以执行内联;因为它可以证明对于这些来说不存在覆盖。考虑到 JIT 也在做这件事,而且做得更好,这将是一项毫无意义的工作。

关于java - 可见性和 javac/JVM 内联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26144822/

相关文章:

java - ElasticsearchSinkConnector 对象映射无法从嵌套更改为非嵌套

java - 如何用 Java 编写正确的微基准测试?

java - antlrworks中导入数据包的问题

java - 如何在启动时在 JVM 中预加载 Web 应用程序类?

java - 弃用的编译错误

java - 如何使 JDK 成为默认的 JRE?

java - 在 Java 中创建默认构造函数

java - 用于插件的 IntelliJ SDK 找不到 com.intellij.tasks

java - 使用 JProgressBar 将数组内容复制到 JTextArea 的进度

java - 配置 : error: Could not detect the location of the Java shared library. 您将需要更新 java.m4 以添加对此 JVM 配置的支持