Java:JVM 将如何优化对 void 和空函数的调用?

标签 java jvm javac

假设我们有以下类:

public class Message extends Object {}

public class Logger implements ILogger {
 public void log(Message m) {/*empty*/}
}

和以下程序:

public static void main(String args[]) {
  ILogger l = new Logger();
  l.log((Message)null); // a)
  l.log(new Message()); // b)
}

Java 编译器会删除语句 ab 吗?在这两种情况下(剥离或不剥离),Java 编译器的决定背后的基本原理是什么?

最佳答案

Will the Java compiler strip out statements a and b ?

javac(源代码到字节码)编译器不会删除任何一个调用。 (通过检查字节码很容易检查这一点;例如,查看 javap -c 输出。)

In both cases (stripping or not stripping), what is the rationale behind the Java compiler's decision ?

符合 JLS :-)。

从务实的角度来看:

  • 如果 javac 编译器优化了调用,Java 调试器将根本看不到它们……这会让开发人员感到困惑。
  • 如果 Message 类和主类是独立编译/修改的,早期优化(通过 javac)将导致破坏。例如,考虑这个序列:

    • Message被编译,
    • 主类编译完成,
    • Message 被编辑,以便 log 做一些事情......并重新编译。

    现在我们有一个编译错误的主类,它在 ab 处没有做正确的事情,因为过早内联的代码已经过时了。


但是,JIT 编译器可能以多种方式在运行时优化代码。例如:

  • 如果 JIT 编译器可以推断不需要虚拟方法调度,则可以内联 ab 中的方法调用。 (如果 Logger 是实现 ILogger 的应用程序使用的唯一类,那么这对于一个好的 JIT 编译器来说是不费吹灰之力的。)

  • 内联第一个方法调用后,JIT 编译器可能会确定主体是 noop 并优化调用。

  • 在第二个方法调用的情况下,JIT 编译器可以进一步推断(通过逃逸分析)Message 对象不需要在堆上分配...或者根本没有。

(如果您想知道 JIT 编译器(在您的平台上)实际上做了什么,Hotspot JVM 有一个 JVM 选项,可以为选定的方法转储 JIT 编译的 native 代码。)

关于Java:JVM 将如何优化对 void 和空函数的调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14207401/

相关文章:

java - 由 : java. lang.ClassNotFoundException : com. mcruiseon.common.Globals.RideType 引起

jvm - Java 8 : Why does Metaspace size increase but number of loaded classes stay the same?

java - Java 6 中的垃圾优先 (G1) 收集器是 "production ready"吗?

eclipse - 这是 eclipse 或 maven-compiler-plugin 错误,还是泛型类转换问题?

java - SBT 设置 javac 最大堆

Java可比合约

java - 一个单独的线程可以更改静态变量吗?

java - 如何从房间数据库返回单个对象?

multithreading - 是否可以使用线程转储找到线程的创建时间?

java - 为什么 Java 不优化 String.split ("regex") 对字符串文字的调用?