临时变量的范围 - Eclipse /编译器是否优化?

时间:2013-01-05 04:04:31

标签: java android scope

首先,我要求那些“过早优化”恐惧症的人免除我:我不想优化任何事情,我只是好奇

我阅读/观察了两件事,包括在stackoverflow上(现在找不到链接):

  • 对于方法调用,所有局部变量的内存保留在方法的“开头”,即使是在较低级别范围内声明的变量(我知道这是不好的措辞)科学地,例如忽略呼叫机制如何工作等,但我希望这一点很清楚)。显然,运行程序不存在范围,它们仅在源代码级别上,以便更好地提供可读性,可维护性,代码结构,告诉编译器我们的意图(例如,给出优化提示,见下文)。
  • 在尽可能小的范围内声明变量的优势之一(即,仍然需要的最高级别)是“编译器可以重用内存其他临时变量(在其他区块中)“。听起来很清楚&对我来说很合理。

我想知道编译器/ JIT /可以实际优化什么,以及什么不能。

以下是以下方法(假设变量实际上是使用的,因此无法对其进行优化):

// The method does many (useful) things, but these were cut here
public void myMethod() {
    int var1 = 1;
    ... // do work
    if (something) {
        int var2 = 2;
        int var3 = 3;
        ... // do work
    }
    int var4 = 4;
    int var5 = 5;
    ... // do work
}

1。)编译器是否能够检测到var2var3的空间是否可以重用var4var5?我不记得在反汇编的字节码中看到过这样的事情。

2。)上面的代码方法是否等同于将方法结尾放到{}的情况?

public void myMethod() {
    int var1 = 1;
    ... // do work
    if (something) {
        int var2 = 2;
        int var3 = 3;
        ... // do work
    }
    {
        int var4 = 4;
        int var5 = 5;
        ... // do work
    }
}

最后,让我们看一个更简单的案例:

public void myMethod() {
    int var1 = 1;
    ... // do work, and then don't refer to var1 any more

    int var4 = 4;
    int var5 = 5;
    ... // do work      
}

3.。)在这种情况下,var1(或var4)可以重用var5个内存吗?即在这种情况下,该方法足以为两个本地int变量提供内存,而不是三个。

(我知道理论上,这些是编译器的明显案例,但有时我会忽略一些事情,例如为什么编译器不能做或假设任何事情。)

2 个答案:

答案 0 :(得分:3)

我可以代表真正的CPU编译器,我不确定JVM编译器,我不认为在编译级别代码的优化程度与你想象的一样(Java平台根本不关心太多关于记忆foorprint,你可以想象)。

对于真正的编译器,这些场景实际上经常被优化。这不是在高级语言级别,而是在RTL级别的较低中间级别。一切都是为了注册分配或堆栈分配,并通过计算函数内部变量的生存集来实现。

这意味着当编译代码时,通过假设任意数量的临时寄存器将所有内容转换为RTL,然后对于每个临时寄存器,通过所谓的live variable analysis计算其实时状态。这只是优化此类事物的方法之一。

例如

  • var1 live scope来自指令1到10
  • var2 live scope来自指令5至17
  • var3 live scope来自指令3至25

这是在将代码拆分为不包含跳转或标签的块之后完成的,这样您就可以确定任何指定块内的流程。

在这个计算之后,您可以很容易地看到大多数时间需要哪些变量,这些变量变得无用并且可以释放它们的预留空间等等。这样做是为了使您能够将尽可能多的变量放入寄存器中并大量优化汇编代码。

我个人认为 javac 不会做任何这样的事情(即使因为JVM是基于堆栈的,所以这只会破坏对象上的内存分配而现在没有任何需要),但我只是猜测

答案 1 :(得分:1)

  1. 是。堆栈插槽可以在嵌套}之后重用,我看过javac就这样做了。

  2. 是。案例1和案例2相同。第二个嵌套{}不会改变任何内容,除非有其后的内容。

  3. Java编译器不会对此进行优化,尽管在理论上给出了它可以想到的所有正确条件。如果变量是最终的,则可能根本不为它们分配插槽。

  4. 您应该注意的另一件事是没有与嵌套}对应的字节代码指令,因此JVM和HotSpot没有基础知道嵌套作用域的结束位置,因此堆栈插槽的使用位置会改变。