GC and assigning values in a for loop

2019-06-11 16:26发布

问题:

I have a friend who told me the following but I couldn't give a good reason why.

someArray =......... 
int a;
for(int i=0; i < someArray; i++) {

a=someArray.get(i).length();
   // Do something
} 

He told me that he declared a outside of the for loop in order to avoid frequent garbage collection.

I thought declaring a inside of the for loop is more readable and thread safe.

However I couldn't disagree that different instances a no of iteration will be garbage collected if it's declared inside of for loop.

Any advise for me?

回答1:

Garbage collection handles objects. What you have is a primitive local variable a which will be allocated on the stack.

Therefore the whole premise of this question is wrong.



回答2:

Try decompiling both versions:

void outside(List<String> someArray) {
  // I've declared this outside the for loop too in order that the
  // the variables i and a are numbered the same in the two versions -
  // this makes no difference with respect to a.
  int i;
  int a;
  for(i=0; i < someArray.size(); i++) {
    a=someArray.get(i).length();
    // Do something
  }
}

void inside(List<String> someArray) {
  for(int i=0; i < someArray.size(); i++) {
    int a=someArray.get(i).length();
    // Do something
  }
}

The resulting bytecode is identical, so there is no performance or behavioural difference.

As such, you should use the one which is more readable, and has variables in tighter scope: declare the variable inside the loop.

  void outside(java.util.List<java.lang.String>);
    Code:
       0: iconst_0
       1: istore_2
       2: iload_2
       3: aload_1
       4: invokeinterface #2,  1            // InterfaceMethod java/util/List.size:()I
       9: if_icmpge     32
      12: aload_1
      13: iload_2
      14: invokeinterface #3,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      19: checkcast     #4                  // class java/lang/String
      22: invokevirtual #5                  // Method java/lang/String.length:()I
      25: istore_3
      26: iinc          2, 1
      29: goto          2
      32: return

  void inside(java.util.List<java.lang.String>);
    Code:
       0: iconst_0
       1: istore_2
       2: iload_2
       3: aload_1
       4: invokeinterface #2,  1            // InterfaceMethod java/util/List.size:()I
       9: if_icmpge     32
      12: aload_1
      13: iload_2
      14: invokeinterface #3,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      19: checkcast     #4                  // class java/lang/String
      22: invokevirtual #5                  // Method java/lang/String.length:()I
      25: istore_3
      26: iinc          2, 1
      29: goto          2
      32: return


回答3:

Since a is not an object which gets created with every loop iteration it will not be garbage collected at all.

Local, non object data types like int, float, bool,... are being kept on a stack. If the variable is out of scope they will be popped from the stack.

In case a would be an object the reference to the object would be removed with every iterration causing the object itself to become not referenced anymore which means it will be GCed at some point in the future.

More information: (Chapter 2.6) https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html