Hi Steven,
On 11/06/2013 4:06 AM, Steven Schlansker wrote:
Hi core-libs-dev,
While doing performance profiling of my application, I discovered that nearly
50% of the time deserializing JSON was spent within String.intern(). I
understand that in general interning Strings is not the best approach for
things, but I think I have a decent use case -- the value of a certain field is
one of a very limited number of valid values (that are not known at compile
time, so I cannot use an Enum), and is repeated many millions of times in the
JSON stream.
I discovered that replacing String.intern() with a ConcurrentHashMap improved
performance by almost an order of magnitude.
I'm not the only person that discovered this and was surprised:
http://stackoverflow.com/questions/10624232/performance-penalty-of-string-intern
I've been excited about starting to contribute to OpenJDK, so I am thinking
that this might be a fun project for me to take on and then contribute back.
But I figured I should check in on the list before spending a lot of time
tracking this down. I have a couple of preparatory questions:
* Has this bottleneck been examined thoroughly before? Am I wishing too hard
for performance here?
* String.intern() is a native method currently. My understanding is that there is a
nontrivial penalty to invoking native methods (at least via JNI, not sure if this is also
true for "built ins"?). I assume the reason that this is native is so the Java
intern is the same as C++-invoked interns from within the JVM itself. Is this an actual
requirement, or could String.intern be replaced with Java code?
As interning is handled inside the VM I've cc'd the hotspot-runtime-dev
alias.
An important point to note here is that the VM has to intern many
Strings itself, hence this is handled in the VM via StringTable::intern.
If you moved this to Java then the VM would need to make Java upcalls
during classloading etc and that would not be good for performance.
David
-----
* If the interning itself must be handled by a symbol table in C++ land as it is today, would a "second
level cache" in Java land that invokes a native "intern0" method be acceptable, so that there
is a low-penalty "fast path"? If so, this would involve a nonzero memory cost, although I assume
that a few thousand references inside of a Map is an OK price to pay for a (for example) 5x speedup.
* I assume the String class itself is loaded at a very sensitive time during VM
initialization. Having String initialization trigger (for example) ConcurrentHashMap
class initialization may cause problems or circularities. If this is the case, would
triggering such a load lazily on the first intern() call be "late enough" as to
not cause problems?
I'm sure that if I get anywhere with this I will have more questions, but this
should get me started. Thank you for any advice / insight you may be able to
provide!
Steven