当前位置: 首页 > 面试题库 >

优化过程中会使用Java内联方法吗?

阴永福
2023-03-14
问题内容

我想知道JVM / javac是否足够聪明

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

string foo()
{
  return bar();
}

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

进入

string a = bar();

或在释放情况下剥离对foo()的不必要调用(因为代码无法到达):

string a = foo(bar());

// bar is the same
...

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

对于第一个示例,我的感觉是肯定的,而对于第二个示例,我的感觉“不确定”,但是有人可以给我一些指针/链接来确认这一点吗?


问题答案:

javac将提供字节码,该字节码是生成该字节码的原始Java程序的忠实表示(在某些可以优化的特定情况下除外: 常量折叠消除死代码
)。但是,当JVM使用JIT编译器时,可以执行优化。

对于第一种情况,JVM似乎支持内联(请参见此处的“

方法”
下的内容,以及有关JVM的内联示例的信息,请参见此处)。

我找不到自己执行方法内联的任何示例javac。我尝试编译一些示例程序(类似于您在问题中描述的程序),即使是,它们似乎都没有直接内联该方法final。这些优化似乎是由JVM的JIT编译器而非进行的javac。下提到的“编译”
的方法
在这里似乎是热点JVM的JIT编译器,而不是javac

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

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和一个iadd300是计算值。private final变量也是如此。如果ab不是静态的,则产生的字节码将是:

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使用了。

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

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

}

如您所见,foo根本不会调用,baz因为该if块内的代码实际上是“死”的。

Sun(现在是Oracle)的HotSpot
JVM结合了字节码的解释和JIT编译。当将字节码提供给JVM时,代码将首先进行解释,但是JVM将监视字节码并挑选出经常执行的部分。它将这些部分覆盖到本机代码中,以便它们可以更快地运行。对于不经常使用的字节码,此编译不会完成。同样也因为编译有一些开销。因此,这实际上是一个权衡的问题。如果决定将所有字节码编译为本机代码,则该代码可能会具有很长的启动延迟。

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

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



 类似资料:
  • 我正在尝试为高度优化的x86-64位操作代码编写一个小型库,并且正在摆弄内联ASM。 在gcc和icc中编译和运行都很好,但是当我检查程序集时,我发现了差异 我在想为什么这么复杂?我正在编写高性能代码,其中指令的数量是关键的。我特别想知道为什么gcc在将变量传递给第二个内联ASM之前会对它进行复制? 尽管gcc决定将变量保存在堆栈中,而不是寄存器中,但我不明白的是,为什么要在将传递给第二个ASM之

  • 本文向大家介绍Android编程使用缓存优化ListView的方法,包括了Android编程使用缓存优化ListView的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Android编程使用缓存优化ListView的方法。分享给大家供大家参考,具体如下: ListView调用Adapter的getView方法获取每一个Item布局,将这些已经获得的Item布局放入缓存,将大大提高获取

  • 本文向大家介绍MySQL延迟关联性能优化方法,包括了MySQL延迟关联性能优化方法的使用技巧和注意事项,需要的朋友参考一下 【背景】   某业务数据库load 报警异常,cpu usr 达到30-40 ,居高不下。使用工具查看数据库正在执行的sql ,排在前面的大部分是: 表的数据量大致有36w左右,该sql是一个非常典型的排序+分页查询:order by col limit N,OFFSET M

  • 本文向大家介绍Android中SparseArray性能优化的使用方法,包括了Android中SparseArray性能优化的使用方法的使用技巧和注意事项,需要的朋友参考一下 之前一篇文章研究完横向二级菜单,发现其中使用了SparseArray去替换HashMap的使用.于是乎自己查了一些相关资料,自己同时对性能进行了一些测试。首先先说一下SparseArray的原理.   SparseArray

  • 本文向大家介绍django-rest-swagger的优化使用方法,包括了django-rest-swagger的优化使用方法的使用技巧和注意事项,需要的朋友参考一下 如下所示: 参考英文文档: http://django-rest-swagger.readthedocs.io/en/latest/ 使用swagger工具结合Django-rest-framework进行restful API的管

  • 问题内容: 我必须修改一个dropwizard应用程序以缩短其运行时间。基本上,此应用程序每天接收大约300万个URL,然后下载并解析它们以检测恶意内容。问题在于该应用程序只能处理100万个URL。当我查看该应用程序时,发现它正在进行许多顺序调用。我想对如何通过使其异步或其他技术来改进应用程序提出一些建议。 所需代码如下:- 我在考虑以下方法: 我直接通过调度程序调用,而不是通过POST调用dro