Why are my variables not out of scope?

Good afternoon everyone

I was taught that when a function returns, the variables (within this function) automatically go out of scope, so we do not need to set them to null.

However, this does not seem to be the case.

I have test code that creates java.lang.ref.PhantomReference pointing to an instance of java.lang.Object . The only strong reference to this object is within function F.

In other words, when this function returns, there should no longer be any strong reference to this object, and now the object must be assembled by GC.

However, no matter how I try to starve in the JVM memory, the GC simply refuses to collect the object. Surprisingly, if I set the variable to null ( obj = null;), GC now collects the object.

What is the explanation for this oddity?

public class Test {
    public static void main(String args[]) {
        // currently testing on a 64-bit HotSpot Server VM, but the other JVMs should probably have the same behavior for this use case
        Test test = new Test();
        test.F(new Object());
    }

    public <T> void F(T obj) {
        java.lang.ref.ReferenceQueue<T> ref_queue = new java.lang.ref.ReferenceQueue<T>();
        java.lang.ref.PhantomReference<T> ref = new java.lang.ref.PhantomReference<T>(obj, ref_queue); // if this line isn't an assignment, the GC wouldn't collect the object no matter how hard I force it to 
        obj = null; // if this line is removed, the GC wouldn't collect the object no matter how hard I force it to
        StartPollingRef(ref_queue);
        GoOom();
    }

    private <T> void StartPollingRef(final java.lang.ref.ReferenceQueue<T> ref_queue) {
        new java.lang.Thread(new java.lang.Runnable() {
            @Override
            public void run() {
                System.out.println("Removing..");
                boolean removed = false;
                while (!removed) {
                    try {
                        ref_queue.remove();
                        removed = true;
                        System.out.println("Removed.");
                    } catch (InterruptedException e) { // ignore
                    }
                }
            }
        }).start();
    }

    private void GoOom() {
        try {
            int len = (int) java.lang.Math.min(java.lang.Integer.MAX_VALUE, Runtime.getRuntime().maxMemory());
            Object[] arr = new Object[len];
        } catch (Throwable e) {
            // System.out.println(e);
        }
    }
}
+5
source share
1 answer

A standard compatible JVM is never required to collect memory. That is, you cannot write a program whose correctness depends on which specific bit of memory is collected at a specific time: you cannot force the JVM to collect (even through System.gc()!) And not rely on it.

Thus, the behavior you observe cannot, by definition, be mistaken: you are deliberately trying to get the environment to do something that does not need to be done.

, , . main, - Java - F. F , T obj .

goOom static main, , . , , , ...

+9

All Articles