优化期间的 Java 内联方法吗? [英] Would Java inline method(s) during optimization?

查看:28
本文介绍了优化期间的 Java 内联方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道 JVM/javac 是否智能到可以转

I wonder if JVM/javac is smart enough to turn

// This line...
string a = foo();

string foo()
{
  return bar();
}

string bar()
{
  return some-complicated-string computation;
}

进入

string a = bar();

或者在 release case 中去掉对 foo() 的不必要调用(因为无法访问代码):

Or strip unnecessary call to foo() in release case (because unreachable code):

string a = foo(bar());

// bar is the same
...

string foo(string b)
{
  if (debug) do-something-with(b);
}

我对第一个例子的感觉是肯定的,而对第二个例子不太确定",但谁能给我一些指示/链接来确认这一点?

My feeling is yes for the first example and "not so sure" for the second one, but could anyone give me some pointers/links to confirm that?

推荐答案

javac 将呈现字节码,它是生成字节码的原始 Java 程序的忠实表示(除非在某些情况下可以优化:不断折叠死代码消除).但是,JVM在使用JIT编译器时可能会进行优化.

javac will present bytecode that is a faithful representation of the original Java program that generated the bytecode (except in certain situations when it can optimize: constant folding and dead-code elimination). However, optimization may be performed by the JVM when it uses the JIT compiler.

对于第一种情况,JVM 似乎支持内联(参见方法此处 并查看 此处 JVM 上的内联示例).

For the first scenario it looks like the JVM supports inlining (see under Methods here and see here for an inlining example on the JVM).

我找不到任何由 javac 本身执行的方法内联的示例.我尝试编译一些示例程序(类似于您在问题中描述的程序),但它们似乎都没有直接内联该方法,即使它是 final.这些优化似乎是由 JVM 的 JIT 编译器完成的,而不是由 javac 完成的.方法下提到的编译器"这里 似乎是 HotSpot JVM 的 JIT 编译器,而不是 javac.

I couldn't find any examples of method inlining being performed by javac itself. I tried compiling a few sample programs (similar to the one you have described in your question) and none of them seemed to directly inline the method even when it was final. It would seem that these kind of optimizations are done by the JVM's JIT compiler and not by javac. The "compiler" mentioned under Methods here seems to be the HotSpot JVM's JIT compiler and not javac.

据我所知,javac 支持死码消除(参见第二种情况的示例)和常量折叠.在常量折叠中,编译器将预先计算常量表达式并使用计算出的值,而不是在运行时执行计算.例如:

From what I can see, javac supports dead-code elimination (see the example for the second case) and constant folding. In constant folding, the compiler will precalculate constant expressions and use the calculated value instead of performing the calculation during runtime. For example:

public class ConstantFolding {

   private static final int a = 100;
   private static final int b = 200;

   public final void baz() {
      int c = a + b;
   }
}

编译为以下字节码:

Compiled from "ConstantFolding.java"
public class ConstantFolding extends java.lang.Object{
private static final int a;

private static final int b;

public ConstantFolding();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public final void baz();
  Code:
   0:   sipush  300
   3:   istore_1
   4:   return

}

注意字节码有一个 sipush 300 而不是 aloadgetfields 和一个 iadd.300 是计算值.private final 变量也是这种情况.如果 ab 不是静态的,则生成的字节码将是:

Note that the bytecode has an sipush 300 instead of aload's getfields and an iadd. 300 is the calculated value. This is also the case for private final variables. If a and b were not static, the resulting bytecode will be:

Compiled from "ConstantFolding.java"
public class ConstantFolding extends java.lang.Object{
private final int a;

private final int b;

public ConstantFolding();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   bipush  100
   7:   putfield    #2; //Field a:I
   10:  aload_0
   11:  sipush  200
   14:  putfield    #3; //Field b:I
   17:  return

public final void baz();
  Code:
   0:   sipush  300
   3:   istore_1
   4:   return

}

这里也使用了 sipush 300.

对于第二种情况(死码消除),我使用了以下测试程序:

For the second case (dead-code elimination), I used the following test program:

public class InlineTest {

   private static final boolean debug = false;

   private void baz() {
      if(debug) {
         String a = foo();
      }
   }

   private String foo() {
      return bar();
   }

   private String bar() {
      return "abc";
   }
}

给出以下字节码:

Compiled from "InlineTest.java"
public class InlineTest extends java.lang.Object{
private static final boolean debug;

public InlineTest();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

private void baz();
  Code:
   0:   return

private java.lang.String foo();
  Code:
   0:   aload_0
   1:   invokespecial   #2; //Method bar:()Ljava/lang/String;
   4:   areturn

private java.lang.String bar();
  Code:
   0:   ldc #3; //String abc
   2:   areturn

}

正如你所看到的,foobaz 中根本没有被调用,因为 if 块中的代码实际上是死的".

As you can see, the foo is not called at all in baz because the code inside the if block is effectively "dead".

Sun 的(现在是 Oracle 的)HotSpot JVM 结合了字节码的解释和 JIT 编译.当字节码呈现给 JVM 时,代码最初被解释,但 JVM 将监视字节码并挑选出经常执行的部分.它将这些部分转换为本地代码,以便它们运行得更快.对于使用频率不高的一段字节码,不做这个编译.这也是因为编译有一些开销.所以这真的是一个权衡问题.如果您决定将所有字节码编译为原生代码,那么代码的启动延迟可能会很长.

Sun's (now Oracle's) HotSpot JVM combines interpretation of the bytecode as well as JIT compilation. When bytecode is presented to the JVM the code is initially interpreted, but the JVM will monitor the bytecode and pick out parts that are frequently executed. It coverts these parts into native code so that they will run faster. For piece of bytecode that are not used so frequently, this compilation is not done. This is just as well because compilation has some overhead. So it's really a question of tradeoff. If you decide to compile all bytecode to nativecode, then the code can have a very long start-up delay.

除了监控字节码之外,JVM 还可以在解释和加载字节码时对字节码进行静态分析,以执行进一步的优化.

In addition to monitoring the bytecode, the JVM can also perform static analysis of the bytecode as it is interpreting and loading it to perform further optimization.

如果您想了解 JVM 执行的特定类型的优化,此页面 非常有帮助.它描述了 HotSpot JVM 中使用的性能技术.

If you want to know the specific kinds of optimizations that the JVM performs, this page at Oracle is pretty helpful. It describes the performance techniques used in the HotSpot JVM.

这篇关于优化期间的 Java 内联方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆