Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable gets garbage collected immediately after catch block

I can see this curious behaviour 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 put a breakpoint on //1 foo is not null and its value is "bar" but in breakpoint //2 foo is null, this can be difficult to understand while you are debug. My question is if there is any specification that says that this is a legal behaviour from the garbage collector

With this small variation it doesn't get 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?

like image 289
Jaime Hablutzel Avatar asked Jul 13 '12 16:07

Jaime Hablutzel


People also ask

How are final variables garbage collected?

Final variables cannot be changed after initial assignment (enforced by the compiler). This does not change the behaviour of the garbage collection as such. Only thing is that these variables cannot be nulled when not being used any more (which may help the garbage collection in memory tight situations).

What triggers garbage collection?

When a JVM runs out of space in the storage heap and is unable to allocate any more objects (an allocation failure), a garbage collection is triggered. The Garbage Collector cleans up objects in the storage heap that are no longer being referenced by applications and frees some of the space.

How does garbage collection take place in Java automatically?

Java garbage collection is an automatic process. The programmer does not need to explicitly mark objects to be deleted. The garbage collection implementation lives in the JVM. Each JVM can implement garbage collection however it pleases; the only requirement is that it meets the JVM specification.

Which variables are eligible for garbage collection?

An object is eligible to be garbage collected if its reference variable is lost from the program during execution. Sometimes they are also called unreachable objects. What is reference of an object? The new operator dynamically allocates memory for an object and returns a reference to it.


1 Answers

In this case, you don't use the foo variable after setting it, so it would even be legal for the JVM to completely ignore the variable as it is never used and that would not change the result of your program.

However that's unlikely to happen in debug mode.

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

EDIT

Actually I get the same behaviour as what you describe in Netbeans 7.1.1 with Java 7.0_03...

One problem might be that because you don't set a default value to foo, you can't use it after the try/catch block (it would not compile).

Bytcode

  • With 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 which case the debugger see 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'm not a bytcode specialist but they look very similar to me...

CONCLUSION

My personal conclusion is that for the debugger to show the value of foo, it has to run a foo.toString() of some sort, which is not a valid statement after the catch block as foo might have not been initialized. Adding a System.out.println(foo) in that section is not legal (does not compile). The debugger is a bit lost as to what the value is and shows null.

To convince yourself that this has nothing to do with 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 
}

On the foobar line, you can see that c holds bar but foo shows as null. So the String is still there, but the debugger can't show it.

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 shows as null, but list contains "bar"... Nice.

like image 99
assylias Avatar answered Sep 22 '22 05:09

assylias