Variable gets garbage collected immediately after blocking

I see this curious behavior from the garbage collector

public class A { public static void main(String[] args) { String foo; try { foo = "bar"; int yoo = 5; //1 } catch (Exception e) { } int foobar = 3;//2 } } 

if I go to debug and set a breakpoint at // 1 foo is not null and its value is a β€œbar”, but at the breakpoint // 2 foo is null, it can be hard to understand while you are debugging. My question is: if there is any specification that says this is the legal behavior of the garbage collector

With this small change, it does not receive garbage collected:

 public class A { public static void main(String[] args) { String foo; try { foo = "bar"; } catch (Exception e) { throw new RuntimeException(e); } int foobar = 3; } } 

Why?

+6
source share
4 answers

In this case, you do not use the foo variable after setting it, so it would be legal for the JVM to completely ignore the variable since it is never used and which will not change the result of your program.

However, this is unlikely to happen in debug mode.

In your case, foo should not get GC'ed as long as it is in scope, or you keep a link to it that includes a section after the try / catch block.

EDIT

Actually, I get the same behavior as in Netbeans 7.1.1 with Java 7.0_03 ...

One problem may be that since you are not setting the default value to foo , you cannot use it after the try / catch block (it will not compile).

Bytcode

  • Using the code you use
 public static void main(java.lang.String[]); Code: 0: ldc #2 // String bar 2: astore_1 3: iconst_5 4: istore_2 5: goto 9 8: astore_2 9: iconst_3 10: istore_2 11: return 
  • Using String foo = null; as the first statement, in this case the debugger sees the value after the try / catch block:
 public static void main(java.lang.String[]); Code: 0: aconst_null 1: astore_1 2: ldc #2 // String bar 4: astore_1 5: iconst_5 6: istore_2 7: goto 11 10: astore_2 11: iconst_3 12: istore_2 13: return 

I am not a specialist in byte coding, but they are very similar to me ...

CONCLUSION

My personal conclusion is that for the debugger to show the value of foo , it should run foo.toString() some type that is not a valid statement after a catch block like foo may not have been initialized. Adding System.out.println(foo) in this section is not legal (does not compile). The debugger is a bit lost relative to the value and shows null .

To convince yourself that this has nothing to do with the GC, you can try the following example:

 public static void main(String[] args){ String foo; char[] c = null; try { foo = "bar"; c = foo.toCharArray(); int yoo = 5; //1 } catch (Exception e) { } int foobar = 3;//2 } 

In the line foobar you can see that c contains bar , but foo shows as null . So, String still exists, but the debugger cannot show it.

An even funnier example:

 public static void main(String[] args){ String foo; List<String> list = new ArrayList<String>(); try { foo = "bar"; list.add(foo); int yoo = 5; //1 } catch (Exception e) { } int foobar = 3;//2 } 

On the foobar line, foo displayed as null , but list contains "bar" ... Nice.

+8
source

foo never has a default value, and when you go to line 2, you go beyond the area in which it was set.

+1
source

The generated byte code is as follows:

  public static void main(java.lang.String[]); Code: 0: ldc #2 // String bar 2: astore_1 3: iconst_5 4: istore_2 5: goto 9 8: astore_2 9: iconst_3 10: istore_2 11: return Exception table: from to target type 0 5 8 Class java/lang/Exception 

My first assumption was that we would reuse the local variable position for foo and foobar, in which case the value would not be available for display during debugging. But as you can see, local 1 is not overwritten (yoo and foobar use the same space).

Since this does not happen, and we can be very sure that the JIT is not doing anything here, this is really strange behavior.

+1
source

This is not legal behavior, as the context of the main method is still alive. Ideally, this should not be GCed unless you declared String foo in the try block (in which case it will not be available in 2).

I tried this code and it works great for me.

-2
source

Source: https://habr.com/ru/post/920438/


All Articles