Does the Java compiler optimize the creation of loop-local variables?

Saucy Goat :

Let's look at this example:

String var;
while (...) {
        var = ...
        // do stuff
}

In this case, we create a reference to a String object and assign different objects to it in each iteration of the loop.

Now, in this other example:

while (...) {
        String var = ...
        // do stuff
}

If we're assuming the compiler is naive, it'll just allocate a reference to a String object on stack every iteration.

Or will it? That is my question - does the (a?) Java compiler perform this optimization? I always leave object declarations in the widest scope possible because I am worried about this, but if the compiler does this already it's one less pebble on my shoe.

Thank you in advance!

Andreas :

it'll just allocate a reference to a String object on stack every iteration.

That's not how it works. Variables on the stack, i.e. parameters and local variables, are allocated (reserved) on method entry.

E.g. if you have code like this:

static void foo() {
    String s;
    for (int i = 0; i < 5; i++) {
        int j = i;
        s = String.valueOf(j);
        bar(s);
    }
    for (int j = 0; j < 5; j++) {
        int k = j;
        s = String.valueOf(k);
        bar(s);
    }
}
static void bar(String s) {
}

For that code, 3 slots1 will be allocated on the stack:

  • s will be in slot 0, and use the slow for the entire method

  • i will be in slot 1, for the duration of the first loop.

  • j will be in slot 2, for the duration of the body of the first loop.

  • Another j will be in slot 1, for the duration of the second loop.

  • k will be in slot 2, for the duration of the body of the second loop.

As you can see, slots 1 and 2 are reused, but there is no "allocation" going on during the method execution. Only the memory allocated/reversed at the beginning of the method.

1) A slot is 4 bytes / 32 bits, i.e. the size of an int or a reference (with compressed Oops).

If you compile with javac -g Test.java and disassemble with javap -v -c Test.class, you get (output from with Java 8):

  static void foo();
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=3, args_size=0
         0: iconst_0
         1: istore_1
         2: iload_1
         3: iconst_5
         4: if_icmpge     24
         7: iload_1
         8: istore_2
         9: iload_2
        10: invokestatic  #2                  // Method java/lang/String.valueOf:(I)Ljava/lang/String;
        13: astore_0
        14: aload_0
        15: invokestatic  #3                  // Method bar:(Ljava/lang/String;)V
        18: iinc          1, 1
        21: goto          2
        24: iconst_0
        25: istore_1
        26: iload_1
        27: iconst_5
        28: if_icmpge     48
        31: iload_1
        32: istore_2
        33: iload_2
        34: invokestatic  #2                  // Method java/lang/String.valueOf:(I)Ljava/lang/String;
        37: astore_0
        38: aload_0
        39: invokestatic  #3                  // Method bar:(Ljava/lang/String;)V
        42: iinc          1, 1
        45: goto          26
        48: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            9       9     2     j   I
           14      10     0     s   Ljava/lang/String;
            2      22     1     i   I
           33       9     2     k   I
           38      10     0     s   Ljava/lang/String;
           26      22     1     j   I

As you can see, the line stack=2, locals=3, args_size=0 shows that it will reserve 3 slots for local variables. The LocalVariableTable at the bottom shows which local variable uses which slot for the duration of which bytecode instructions (scope).

Moving the declaration of s inside the loops will rearrange the order in which variables are assigned to slots, i.e. which slots they use, and changes the length of the scope of s, but that's it.

static void foo() {
    for (int i = 0; i < 5; i++) {
        int j = i;
        String s = String.valueOf(j);
        bar(s);
    }
    for (int j = 0; j < 5; j++) {
        int k = j;
        String s = String.valueOf(k);
        bar(s);
    }
}
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            9       9     1     j   I
           14       4     2     s   Ljava/lang/String;
            2      22     0     i   I
           33       9     1     k   I
           38       4     2     s   Ljava/lang/String;
           26      22     0     j   I

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=19105&siteId=1