Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm reading about WeakReference in wikipedia and I saw this code

public class ReferenceTest {
        public static void main(String[] args) throws InterruptedException {

            WeakReference r = new WeakReference(new String("I'm here"));
            WeakReference sr = new WeakReference("I'm here");

            System.out.println("before gc: r=" + r.get() + ", static=" + sr.get());
            System.gc();
            Thread.sleep(100);

            // only r.get() becomes null
            System.out.println("after gc: r=" + r.get() + ", static=" + sr.get());

        }
}

When It runs this is the result

before gc: r=I'm here, static=I'm here

after gc: r=null, static=I'm here

sr and r variable are both referring string objects. r is now garbage collected but, why sr didn't garbage collected after calling garbage collector?

I'm just curious how this happened.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
206 views
Welcome To Ask or Share your Answers For Others

1 Answer

It is NOT because of string pooling per se.

The real reason is that the ReferenceTest class has an implicit hard reference to the String object that represents the "I'm here"literal. That hard reference means that the weak reference in sr won't be broken by the garbage collection1.

In fact:

  • The implicit reference would be necessary, even if String objects corresponding to literals weren't pooled. (They are pooled ... the JLS effectively requires this ... but I'm saying the references would required even if they weren't. The alternative would be for Java to create and "intern" a fresh String object each time a string literal expression was evaluated. That would be horribly inefficient!!)

  • The string pool internally uses a form of weak reference ... so that unreferenced interned strings can be garbage collected. If that weren't the case, then calling String.intern() would potentially be an incurable memory leak.

Anyway ... if you carefully construct a string without using a string literal and intern it, like this:

    char[] chars = {'a', 'b', 'c'};
    WeakReference r = new WeakReference(new String(chars).intern());

... you should find that the weak reference is (eventually) broken. (It might take a couple of GC cycles though.)


1 - In theory, causing the class to be unloaded and garbage collected could get rid of the last reachable hard reference to that String literal. However, if that happened in this case, you'd be past the point at which you'd be able to observe the state of the WeakReference object. At least, in with your example code. Besides, unless you boot your JVM with a custom class loader, I don't think it would be possible to cause the unloading of the entrypoint class. It's not the kind of thing that is easy, or useful to do.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...