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.
YAT_Archivista at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 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 ?

MarekKa at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 3
> both object s1 and s2 can be garbage collectedNope. They're still in scope.
ejpa at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 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.
MarekKa at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 5
It doesn't when I run it. I suspect you haven't posted the actual code you compiled.
YAT_Archivista at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 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

stefan.schulza at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 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.
_dnoyeBa at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 8
The exact version of JRE on which I tested the code is 1.6.0-b105 ?on which version are you testing?
MarekKa at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 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.

YAT_Archivista at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 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");

}

}

MarekKa at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 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 > top of Java-index,Core,Core APIs...
# 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

MarekKa at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 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 > top of Java-index,Core,Core APIs...
# 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].

Captain.Obviousa at 2007-7-11 23:35:49 > top of Java-index,Core,Core APIs...
# 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.

_dnoyeBa at 2007-7-21 19:58:00 > top of Java-index,Core,Core APIs...
# 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.
jschella at 2007-7-21 19:58:00 > top of Java-index,Core,Core APIs...
# 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.

_dnoyeBa at 2007-7-21 19:58:00 > top of Java-index,Core,Core APIs...
# 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.

jschella at 2007-7-21 19:58:00 > top of Java-index,Core,Core APIs...