WeakReferenced object is not garbage collected after calling System.gc()

后端 未结 2 555
北荒
北荒 2021-01-16 14:17

I am a fresh new learner of Java. I\'m now learning the concept of WeakReference. I came across a problem which probably looks stupid but I just wanna figure out the reason.

相关标签:
2条回答
  • 2021-01-16 15:00

    Firstly, System.gc() does not ensure a garbage collection. Instead, it's just a hint that "It's a good time to run garbage collection".

    Secondly, in your code when you put A a1 = wr.get(); before calling System.gc(), it creates a new strong reference to the same object referenced by a, thus even if garbage collection runs, your object will not be garbage collected.

    As we have two tasks in hand

    1. Ensure garbage collection
    2. Don't keep any strong reference to the object you want to be garbage collected

    Let's do little modification to your code

    public class A {
        public static void main(String[] args) {
            A a = new A();
            WeakReference<A> wr = new WeakReference<>(a);
            a = null;
            // A a1 = wr.get(); Removing this, this does our 2nd task
            System.out.println(a);
            // System.out.println(a1); Removing this as a1 does not exists anymore
            try {
                while (null != wr.get()) { // 1st task done, the loop ensures sending the hint until your object collected
                    System.gc();
                    // Thread.sleep(10000); it does not have impact
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(wr.get()); // Obviously prints null
        }
    
        @Override
        protected void finalize() {
            System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
        }
    }
    
    0 讨论(0)
  • 2021-01-16 15:16

    The premise of your test is flawed. System.gc() is only a hint to run the garbage collector. It is frequently ignored.

    From the documentation:

    Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.

    (Emphasis mine)

    In future, you may use the VM options -verbose:gc and -XX:+PrintGCDetails to see what the garbage collector is doing.


    More importantly, you are also very quickly taking the reference out of the weak reference and putting it back into a strong reference:

    A a = new A();
    WeakReference<A> wr = new WeakReference<>(a);
    a = null; // no strong references remain
    A a1 = wr.get(); // the instance now has a strong reference again
    

    Unless garbage collection occurs between these exact two instructions, the object will not be garbage collected.

    If you remove a1, your code behaved as you would expect when I ran it (though, because of the first part of my answer, your mileage may vary):

    class A
    {
        public static void main(String[] args)
        {
            A a = new A();
            WeakReference<A> wr = new WeakReference<>(a);
            a = null;
    
            System.out.println(a);
    
            try {
                System.gc(); // instance of A is garbage collected
                Thread.sleep(10000);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            System.out.println(wr.get());
        }
    
        @Override
        protected void finalize( )
        {
            System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
        }
    }
    
    0 讨论(0)
提交回复
热议问题