Once a String literal gets referenced by the constant pool, does it ever get taken out of memory? Possibly such as the class it was coded in gets GC'ed and the class which created the String literal is no longer in the heap? Or is it that once the String literal reference is in the constant pool, there is always a reference to the String so it is always taking up memory?
I'm dealing with a memory sensitive application so any info on this matter would be much appreciated.
Unfortunately, the article is not correct in this respect - string literals (and other Strings in the intern pool) can be collected. But it requires unusual circumstances. Before the literal String can be collected, the class that uses the literal must itself be collected. And most ClassLoaders keep a reference to each class they load. So generally the class can't be collected unless first the ClassLoader that loaded it is collected. If you're not using multiple class loaders, this won't happen. But in an environment like an application server, it happens quite routinely when an application is reloaded.
More generally: using Sun's JDKs (all the versions I'm aware of), if a String got put in the intern pool by the intern() method, it can be garbage collected as soon as any other references to the String are removed. The intern pool is roughly equivalent to a WeakHashMap, and does not prevent garbage collection as long as no other references exist. Pooled strings will have been placed in a section of the heap known as the "permanent generation", however this name is misleading. It means that objects in this area are expected to live a long time, usually for the life of the JVM, and therefore garbage collection here is infrequent compared to other parts of the heap. However, that doesn't mean it never happens. Using standard Sun JDKs, it can and does. This behavior is not guaranteed though, so it could change for some future JDK, or a JDK from some provider other than Sun.
To observe GC of literals, try this:
To make this work, after compiling both classes, you need to move (not copy) file StringLiteralHolder.class into a directory called not_in_classpath. (If the class file were in the standard classpath, it would be loaded by a parent ClassLoader rather than the intended URLClassLoader, and this parent ClassLoader would not be collected.) Using System.identityHashCode(), we can observe that the class gets loaded by two different ClassLoader instances, and the field literal refers to two different String instances.
This only works because the class gets completely unloaded, and the String referenced by the literal gets collected, before the class is reloaded. No overlap. If the class had been reloaded by a second ClassLoaderwhile the first was still loaded, we could get a second Class instance for a duplicate copy of the class -- but the literal in the second class would refer to the same pooled String instance. There is only one String intern pool, even with multiple classloaders.
"I'm not back." - Bill Harding, Twister
Joined: Oct 30, 2001
Is there anything you can do about that misleading article? I took it that an article on JavaRanch would be "gospel".
Before I read that article, I believed that String literals got GCd when all associated classes did, and that classes could be GCd if there were multiple ClassLoaders. From what you have now written, I guess I was right in the first place, yes? [ May 03, 2007: Message edited by: Peter Chase ]