0
class Sample {

    int a;

    public void abcx() {
        for (int i = 0; i < 5; i++) {
            if (i % 2 == 0) {
                int b = i;
            }
        }
    }
}

How often gets b allocated?

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958

2 Answers2

7

Please take a look at nhahtdh answer. It is good, as it cites the relevant sections of JLS.

I don't delete this answer, as I hope that it gives you some hints how to find such answers (or at least good guesses) by yourself for future questions. It also might provide some additional explanations to your example code.

First of all: If it comes to "what does Java do in case XYZ" you should often be really asking "what does my JVM do in case XYZ". If you want to answer questions about Java itself, you should be able to reference to Java Language Specification.

edit: See nhahtdh answer for this reference.

What happens in your example code?

I guess the best guess you can make is with Java Bytecode. Now there is a difference between loading an object / data structure / primitive type and allocating one.

To allocate an object means you give it some space where it can be stored. Its only a place holder. To load with aload_0 means an object referece gets pushed on the operand stack. The next operation will take its operands from the operand stack.

javac Sample.java
javap -c Sample.class

gives you Java Bytecode:

Compiled from "Sample.java"
class Sample {
  int a;

  Sample();
    Code:
       0: aload_0    // load int a
       1: invokespecial #1  // Method java/lang/Object."<init>":()V (every class is a child class of Object)
       4: return        

  public void abcx();
    Code:
       0: iconst_0      // get 0 on stack
       1: istore_1      // store 0 to variable 1 (int i=0)
       2: iload_1       // load 0 from variable 1 (load 0 from i)
       3: iconst_5      // load 5 from
       4: if_icmpge     21 // i<5 (21 means: jump to line 21 if i >= 5)
       7: iload_1       // load i
       8: iconst_2      // load 2
       9: irem          // i%2
      10: ifne          15 // if(i%2!=0) jump to line 15
      13: iload_1       // load i
      14: istore_2      // b=i
      15: iinc          1, 1 // i++
      18: goto          2 // back to loop condition
      21: return        
}
  • aload_0 : loads an object referece on the operand stack (source)
  • iconst_n : These are used to push the constant ints 0 through 5 onto the stack. (source)
  • istore_1 :stores the integer on the top of the stack into variable 1
  • invokespecial : (source)
  • if_icmpge : pops the top two ints off the stack and compares them. If value2 is greater than or equal to value1, execution branches to the address (source)
  • irem: Pops two ints off the operand stack, divides value2 by value1 (i.e. value2 / value1), computes the remainder and pushes the int remainder back onto the stack (source)

Answer to your allocation question

I'm not sure about the correct answer. I guess user Budda could be right: edit: No, Budda is wrong. But lets explain why it was a good guess.

It is allocated once when i is 0, and then when i is 2 and again when i is 4. So 3 in total.

As soon as } gets closed, the scope of b is over. So it should be "deleted" by Garbage collector, as b has no reference on it. But you have to consider that primitive data types are not on the heap and only the heap is managed by the garbage collector (source).

When you take a look at the byte code above, you might notice that b is only changed in one line (istore_2). So you might want to take a look at the memory layout of processes.

I am not sure if the following is also true for Java programs, but it is true for processes in x86. Processes look like this in memory:

enter image description here Source: My blog :-) It was an assignment of a operating systems class.

You can see that primitive data types have own sections in memory layout. So I guess it gets allocated once when the class is loaded. But I can't give you sources for this guess and I am not sure about it.

edit: See also The Architecture of the Java Virtual Machine.

Community
  • 1
  • 1
Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
  • 3
    +1 for suggesting having a look. An even better answer would include an explanation for people like me who can't read javap output quickly. – Duncan Jones May 01 '13 at 07:41
  • 3
    There is no "allocation" shown here. The bytecode only shows the local variable being loaded or stored. – nhahtdh May 01 '13 at 07:41
  • I'm assuming that the user is very new to programming by looking at question. Infact, I also don't understand how to read and understand byte code. Can you elaborate what really is happening with b? I don't see it created. – Buddha May 01 '13 at 07:43
  • Use this reference instead: http://www.vmth.ucdavis.edu/incoming/Jasmin/ref-aload__l.html – nhahtdh May 01 '13 at 07:45
  • 1
    No, it is allocated only once. Later are only read and write. – nhahtdh May 01 '13 at 08:11
  • @nhahtdh: Thanks for your answer and comments. I often miss the relevant sections of JLS. I hope your answer gets accepted, although my has more upvotes. – Martin Thoma May 01 '13 at 08:28
  • @nhahtdh The references cited in this question and by you are non-normative. The [Java Virtual Machine Specification](http://docs.oracle.com/javase/specs/jvms/se7/html/index.html) is already a perfectly adequate, normative reference. Moose's own blog is hardly an independent citation either. – user207421 May 01 '13 at 10:10
  • @EJP: You mean the aload (for the reference that I suggested here)? – nhahtdh May 01 '13 at 10:13
3

It is allocated once, since the array of local variables in a frame is allocated when a frame is created per method invocation.

From JVM Specification - Section 2.6 - Frames (emphasis mine)

A frame is used to store data and partial results, as well as to perform dynamic linking, return values for methods, and dispatch exceptions.

A new frame is created each time a method is invoked. A frame is destroyed when its method invocation completes, whether that completion is normal or abrupt (it throws an uncaught exception). Frames are allocated from the Java Virtual Machine stack (§2.5.2) of the thread creating the frame. Each frame has its own array of local variables (§2.6.1), its own operand stack (§2.6.2), and a reference to the run-time constant pool (§2.5.5) of the class of the current method.

From JVM Specification - Section 2.6.1 - Local Variables (emphasis mine)

Each frame (§2.6) contains an array of variables known as its local variables. The length of the local variable array of a frame is determined at compile-time and supplied in the binary representation of a class or interface along with the code for the method associated with the frame (§4.7.3).

I am not sure whether the JVM will optimize the whole method away, since the code in the method does not write to anything apart from local variables.


As for the output of javap. You need to compile your program with -g to generate all debug information (including the table of local variables for each method). Then run javap with -v (-verbose) flag to make it output the number of local variables, and -l flag to make it output the local variable table for each method.

javac -g Sample.java
javap -c -l -v Sample

This is the trimmed down output, which contains only abcx() method:

public void abcx();
  LineNumberTable:
   line 6: 0
   line 8: 7
   line 10: 13
   line 6: 15
   line 13: 21

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   15      0      2    b       I
   2      19      1    i       I
   0      22      0    this       LSample;


  Code:
   Stack=2, Locals=3, Args_size=1
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   iconst_5
   4:   if_icmpge       21
   7:   iload_1
   8:   iconst_2
   9:   irem
   10:  ifne    15
   13:  iload_1
   14:  istore_2
   15:  iinc    1, 1
   18:  goto    2
   21:  return
  LineNumberTable:
   line 6: 0
   line 8: 7
   line 10: 13
   line 6: 15
   line 13: 21

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   15      0      2    b       I
   2      19      1    i       I
   0      22      0    this       LSample;

  StackMapTable: number_of_entries = 3
   frame_type = 252 /* append */
     offset_delta = 2
     locals = [ int ]
   frame_type = 12 /* same */
   frame_type = 250 /* chop */
     offset_delta = 5


}

Note that Locals=3 means that there are 3 local variables in the frame, but it doesn't necessarily mean that there are 3 local variables in the code. The definition of "local variable" is different for the code and the JVM. Read JVM Specification - Section 2.6.1 - Local Variables for more information.

The Start and Length field in local variable table denotes the scope of the variable, with respect to the Code table. Slot are the slot numbers used by load and store instructions. Name is the name of the variable in the source code. Signature is a string that encodes the type of the variable. This is described in JVM Specification - Section 4.7.13 - The LocalVariableTable Attribute

Community
  • 1
  • 1
nhahtdh
  • 55,989
  • 15
  • 126
  • 162