Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is a Java local variable eligible for GC?

Tags:

java

Given the following program:

import java.io.*;
import java.util.*;

public class GCTest {

    public static void main(String[] args) throws Exception {
        List cache = new ArrayList();
        while (true) {
            cache.add(new GCTest().run());
            System.out.println("done");
        }
    }

    private byte[] run() throws IOException {
        Test test = new Test();
        InputStream is = test.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buff = new byte[256];
        int len = 0;
        while (-1 != (len = is.read())) {
            baos.write(buff, 0, len);
        }
        return baos.toByteArray();
    }

    private class Test {
        private InputStream is;

        public InputStream getInputStream() throws FileNotFoundException {
            is = new FileInputStream("GCTest.class");
            return is;
        }

        protected void finalize() throws IOException {
            System.out.println("finalize");
            is.close();
            is = null;
        }
    }
}

would you expect the finalize to ever be called when the while loop in the run method is still executing and the local variable test is still in scope?

More importantly, is this behaviour defined anywhere? Is there anything by Sun that states that it is implementation-defined?

This is kind of the reverse of the way this question has been asked before on SO where people are mainly concerned with memory leaks. Here we have the GC aggressively GCing a variable we still have an interest in. You might expect that because test is still "in scope" that it would not be GC'd.

For the record, it appears that sometimes the test "works" (i.e. eventually hits an OOM) and sometimes it fails, depending on the JVM implementation.

Not defending the way this code is written BTW, it's just a question that came up at work.

like image 390
Dave Griffiths Avatar asked Sep 01 '09 15:09

Dave Griffiths


1 Answers

While the object won't be garbage collected if it is still in scope, the JIT compiler might take it out of scope if the variable isn't actually used any further in the code (hence the differing behavior you are seeing) even though when you read the source code the variable still seems to be "in scope."

I don't understand why you care if an object is garbage collected if you don't reference it anymore in code, but if you want to ensure objects stay in memory, the best way is to reference them directly in a field of a class, or even better in a static field. If a static field references the object, it won't get garbage collected.

Edit: Here is the explicit documentation you are looking for.

> I'm assuming an object cannot die before a local reference to it has gone out of scope.

This can not be assumed. Neither the Java spec nor the JVM spec guarantees this.

Just because a variable is in scope, doesn't mean the object it points to is reachable. Usually it is the case that an object pointed to by an in-scope variable is reachable, but yours is a case where it is not. The compiler can determine at jit time which variables are dead and does not include such variables in the oop-map. Since the object pointed to by "nt" can [sic - should be cannot] be reached from any live variable, it is eligible for collection.

like image 117
Yishai Avatar answered Sep 28 '22 08:09

Yishai