【问题标题】:Is there a list of optimizations done by javac and hotspot?是否有 javac 和热点完成的优化列表?
【发布时间】:2016-05-27 18:35:17
【问题描述】:

我最近一直在与同事讨论什么是好的代码。具体来说,出现了循环内分配的问题。我见过多种情况(在其他语言中),在循环中分配变量可能会受到严重惩罚,而我一次又一次地经历和看到的智慧指出,最好避免这些明显危险的事情。

但是,这似乎不是widely accepted,许多人建议应该依靠热点和javac 来修复任何明显的错误,例如在循环内分配,事实上鼓励实践。

我在 Java 中对此很好,因为它似乎一直为您提升变量的声明而没有不良影响。但我不知道鼓励哪些其他错误作为最佳实践。当有人告诉我做这样的事情时,我是否可以使用资源来验证行为?

【问题讨论】:

  • 你的问题对我来说听起来很广泛。一般来说,我认为“资源”是一个运行时分析器。
  • answered this question 表明编译的字节码对于在循环内部和外部声明的变量是相同的。它甚至不在 JVM 级别:javac 消除了差异。
  • 他说的是“分配”,但我猜他的意思是打电话给new(或其他语言,malloc)。
  • @markspace 我知道它很广泛,我的问题主要是我不知道我不知道什么——而且我还没有找到任何可以说明我可以期待什么样的优化的东西来自 javac/hotspot。
  • @markspace 我也指分配指针。不是new,而是声明。

标签: java javac jvm-hotspot


【解决方案1】:

好像有很大的误会。比较时

String str;
while(condition){
    str = calculateStr();
    .....
}

while(condition){
    String str = calculateStr();
    .....
}

实际操作,calculateStr() 和结果字符串的分配,总是发生在循环内。所以在这两种情况下,都需要HotSpot去判断calculateStr()里面的操作是否不变,是否可以移出循环。

相比之下,局部变量存在于栈帧中,一个在方法入口分配并在方法出口释放的数据结构(虽然“分配”和“释放”通常仅意味着“移动堆栈”指针”) 并且足够大以容纳在方法执行期间可能同时存在的所有局部变量。

因此,无论哪种情况,堆栈帧内都必须有一个位置来保存str 的值(在字节码级别,局部变量通过索引访问)。但有趣的一点是,如果您有多个局部变量,缩小变量的范围可能会减少通过启用堆栈帧中变量的内存位置的重用来减少所需的内存。

所以当你写的时候:

String one;
int two;
while(condition1){
    one = calculateStr();
    .....
}
while(condition2){
    two = calculateInt();
    .....
}

您的堆栈框架中有两个变量,映射到onetwo。相反,当你写:

while(condition1){
    String one = calculateStr();
    .....
}
while(condition2){
    int two = calculateInt();
    .....
}

堆栈帧中只有一个局部变量,在第一个循环中映射到one,在第二个循环中映射到two


也许您首先需要了解,局部变量的声明及其超出范围都不会产生任何成本。如前所述,每个局部变量在堆栈帧中都有其预定位置,并且堆栈帧在方法入口处分配并持续整个方法执行。变量在写入实际值时生效,这在所有变体中都发生在同一位置,当它超出范围时,什么也不会发生。当它稍后被重用时,新值的实际写入,甚至可能是不同类型的,都会建立新变量,尽管从 JVM 的角度来看,它是相同还是不同的变量都没有关系.

换句话说,局部变量的名称和范围,在某种程度上,甚至是类型,只是源代码级别的工件(除了调试元信息)。在字节码级别,它们永远不会被创建或销毁,只会被写入和读取。但是限制源代码范围可以为不同的变量重复使用相同的位置,从而有可能减少堆栈帧的大小。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    • 2011-12-12
    • 2013-05-02
    • 1970-01-01
    • 2010-11-30
    • 2011-06-27
    • 2019-09-17
    相关资源
    最近更新 更多