John said:
That's an interesting article; thanks for pointing it out. The
article's premise is slightly flawed, but the code (the first example,
at least) works.
I will therefore have to retrench, and say that when
you intern() a String you *may* ensure that a copy is retained for the
remainder of the VM's lifetime. Whether or not that is is in fact
ensured depends on the String implementation [not on the VM
implementation, as the JW article's author mistakenly implied].
It certainly doesn't /depend/ on the JVMs implementation. I think the author's
reasoning was (or rather, should have been ;-) that in the specific JVM he was
testing, String interning /is/ done by the JVM -- in the discussion afterwards
he talks of the interned String data being kept outside the heap.
Incidentally, I can't see the sense of that implementation decision: either the
implementation is simple-minded and does not reclaim interned Strings, in which
case it makes sense to keep the data in a special non-GCable area outside the
heap; or it does reclaim them, in which case the sensible approach is to use a
weak collection (or perhaps just the JVM's underpinnings for weak collection)
and it would be pointless to store them anywhere except the heap -- which is,
after all, designed for that kind of thing.
Changing the subject slightly. It's not completely clear to me that it is
legal for the JVM to recycle interned Strings in this way -- at least not it if
has observable consequences (other than not-running-out-of-memory ;-) and
System.identityHash() is certainly observable. The contract of intern() is
perhaps not strong enough to rule this optimisation out for "normal" strings
(and in any case, I'm not sure that the JavaDocs are normative). However the
contract in the JLS2 for the String literals does not (IMO) leave any scope for
/any/ observable recycling of the corresponding objects -- the language is
unambiguous and repeated. What's more the interning of Sting literals is
discussed (briefly) in the context of class loading, so it would not be easy to
argue that the JLS writers had just "forgotten" this issue.
The obvious (and preferable, IMO) fix would be to weaken the language of the
JLS in its next edition. Alternatively, the implementation could "pin"
interned Strings when their identityHash() is evaluated, and make them
non-recyclable at that time (say by adding a strong ref to the String to some
internal list).
As it stands (and despite the article's assertion) I don't see any reason to be
confident that:
class Oddity
{
static final int aHash = System.identityHash("Hello");
static bool check() { return aHash == System.identityHash("Hello"); }
}
cannot false from Oddity.check().
-- chris