我想知道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
替代aload
的getfield
S和一个iadd
。300
是计算值。private final
变量也是如此。如果a
和b
不是静态的,则产生的字节码将是:
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