WeakReference and interned strings.
Hi
I have question. Why line
out.println("weakS2 = " + weakS2.get());
retuning 搒s?... despite we don抰 have control over gc, in this situation we should get null (at least I think I should get null :-) ).
揑n the early JDKs, any string you interned could never be garbage collected because the JVM had to keep a reference to in its Hashtable so it could check each incoming string to see if it already had it in the pool. With JDK 1.2 came weak references. Now unused interned strings will be garbage collected.?br>
Code:
importstatic java.lang.System.out;
import java.lang.ref.WeakReference;
publicclass Main{
publicstaticvoid main(String[] args){
out.println("Begin");
String s1 =new String("ss");//string created in fly
String s2 ="ss";//interned strings
WeakReference<String> weakS1 =new WeakReference<String>(s1);
WeakReference<String> weakS2 =new WeakReference<String>(s2);
System.gc();
for (int i = 0; i < 1000000; i++){//creating objects - I want to force gc to work
String a ="dsakfljsdklf jdslghdfjg hfg hjkfhg akfh" + i;
}
System.gc();
out.println("weakS1 = " + weakS1.get());//good, I wanted null
out.println("weakS2 = " + weakS2.get());// return "ss" - why?
out.println("End");
}
}
[2325 byte] By [
MarekKa] at [2007-11-27 1:01:02]

# 1
s1 and s2 still hold strong references to the strings.
# 2
Yes, it抯 true that s1 and s2 are strongly reachable but after the line WeakReference<String> weakS2 = new WeakReference<String>(s2); both object s1 and s2 can be garbage collected, leaving only weak reference in objects weakS1 and weakS2.
In line out.println("weakS1 = " + weakS1.get()); at this moment s1 and weak reference to object s1 in weakS1 were garbage collected, because weakS1.get() return null; the same thing should be with s2 ?
# 3
> both object s1 and s2 can be garbage collectedNope. They're still in scope.
ejpa at 2007-7-11 23:35:49 >

# 4
Ok, if s1 is still in scope (strong reference to object) and weakS1 points also on the same object(but with week reference) then why weakS1.get() return null?Object can抰 be garbage collected if they are strongly reachable.
# 5
It doesn't when I run it. I suspect you haven't posted the actual code you compiled.
# 6
No, the code is correct. I have the same effect here either using eclipse or java6 to run it.
Maybe it's to do with new String() creating a copy of the parameter rather than storing it.
Fascinating.
€dit. I just tried some more variations. s2 not being null seems to have to do with it being a string assignment, which is not compiled to some new String() statement but a direct reference to the String. s1 being null may be caused by compiler optimization, as it is not referenced afterwards anymore. If you do reference it later on, also the WeakReference remains non-null. I assume, that the "object" of type String is GCable, while the "constant" string is not.
Message was edited by: stefan.schulz
# 7
> It doesn't when I run it. I suspect you haven't> posted the actual code you compiled.I'm with you on this one.
# 8
The exact version of JRE on which I tested the code is 1.6.0-b105 ?on which version are you testing?
# 9
> I have the same effect here either using eclipse or java6 to run it.
I see. With that information I've managed to reproduce it too:
$ /usr/local/lib/jdk1.6.0_01/jre/bin/java Main
Begin
weakS1 = null
weakS2 = ss
End
$ /usr/local/lib/jdk1.5.0/jre/bin/java Main
Begin
weakS1 = ss
weakS2 = ss
End
You're probably right about the optimisation.
# 10
> I assume, that the "object" of type String is GCable, while the "constant" string is not.
I assume the same but ?br>
揑n the early JDKs, any string you interned could never be garbage collected because the JVM had to keep a reference to in its Hashtable so it could check each incoming string to see if it already had it in the pool. With JDK 1.2 came weak references. Now unused interned strings will be garbage collected.?
Can anyone write (or modify my code) a complete code sample which:
1) create strong reference to interned strings
2) create a weak reference to that object
3) losing the strong reference or setting it to null
4) run gc
5) printing the contend of weak reference and get the null value
Small modification of my above code. Added setting variable s1 and s2 to null after creating weak reference.
import static java.lang.System.out;
import java.lang.ref.WeakReference;
public class Main {
public static void main(String[] args) {
out.println("Begin");
String s1 = new String("ss");//string created in fly
String s2 = "ss";//interned strings
WeakReference<String> weakS1 = new WeakReference<String>(s1);
WeakReference<String> weakS2 = new WeakReference<String>(s2);
s1 = null;
s2 = null;
System.gc();
for (int i = 0; i < 1000000; i++) {//creating objects - I want to force gc to work
String a = "dsakfljsdklf jdslghdfjg hfg hjkfhg akfh" + i;
}
System.gc();
out.println("weakS1 = " + weakS1.get());//good, I wanted null
out.println("weakS2 = " + weakS2.get());//suprisly it return "ss" - why?
out.println("End");
}
}
# 11
What is the point here? System.gc() is only a hint, and you have no guarantee that it ever did anything, or that GC will ever run at all.But if you're worrying about whether WeakReferences really work as advertised, don't.
ejpa at 2007-7-11 23:35:49 >

# 12
True, System.gc() is only hint to free memory, but what we can tell is when object can be garbage collected.
For now, I think that interned string can抰 be garbage collected.
The WeakReference is simplified problem of my WeakHashMap in which I use interned string as keys. The entries allocated that way, aren抰 free, even when I lose strong reference to key
# 13
> For now, I think that interned string can抰 be> garbage collected.Well you're free to think what you like I suppose, but your test doesn't prove anything and the Sun documentation says the opposite.
ejpa at 2007-7-11 23:35:49 >

# 14
> 揑n the early JDKs, any string you interned could
> never be garbage collected because the JVM had to
> keep a reference to in its Hashtable so it could
> check each incoming string to see if it already had
> it in the pool. With JDK 1.2 came weak references.
> Now unused interned strings will be garbage
> collected.?
And where, exactly, does this quote come from?
It doesn't come from the JDK 1.6 documentation for [url=http://java.sun.com/javase/6/docs/api/java/lang/String.html#intern()]String.intern()[/url].
# 15
If the string is interned then its reclamation will depend upon the internment algorithm. I would not use an interned string for any type of weakhashmap key or anything. That algorithm is likely not part of the JVM spec and probably can change depending on the JVM you are running.
This reclaim of s1 might be a new optimization. Perhaps allowed by the more recent JLS!?
Also you can try putting all your code inside of a method and call that method from main. Then after that method call, do a gc. Its harder for the gc to reclaim objects created within the same method (or the same stack depth) as the gc call.
# 16
> What is the point here? System.gc() is only a hint,> and you have no guarantee that it ever did anything,> or that GC will ever run at all.> In the Sun VMs that call does something every time.
# 17
> > What is the point here? System.gc() is only a
> hint,
> > and you have no guarantee that it ever did
> anything,
> > or that GC will ever run at all.
> >
>
> In the Sun VMs that call does something every time.
So true. A lot of people hold that common misconception. System.gc causes the GC to run just as the javadoc says it does. What it can not do is tell the GC how deep to look for reclaimable objects.
# 18
> > In the Sun VMs that call does something every
> time.
>
> So true. A lot of people hold that common
> misconception. System.gc causes the GC to run just
> as the javadoc says it does. What it can not do is
> tell the GC how deep to look for reclaimable
> objects.
It is certainly deep enough to clean up custom class loaders though.