ClassValue perf?

Peter Levart peter.levart at gmail.com
Sat May 2 22:32:45 UTC 2015


Hi,

I have considered using ClassValue in the past because it is quite fast 
(as fast as a hash table can be) but was afraid of footprint overhead, 
because I saw with debugger a structure being grown before my eyes that 
was quite complicated and that I could not understand entirely. Now I 
took some time to actually try to understand and measure it. In a 
typical scenario ClassValue was designed for (initial capacity == 32), 
initializing for example 16 ClassValues x 1024 Classes, jmap shows the 
following interesting entries which all amount to overhead (that's on 
64bit JVM with compressed OOPS):


  num     #instances         #bytes  class name
----------------------------------------------
    1:         16384         655360 java.util.WeakHashMap$Entry
    2:         16402         524864 java.lang.ClassValue$Entry
    8:          1024         147456 [Ljava.util.WeakHashMap$Entry;
    9:          1025         147480 [Ljava.lang.ClassValue$Entry;
   13:          1024          65536 java.lang.ClassValue$ClassValueMap
   17:          1024          32768 java.lang.ref.ReferenceQueue
   21:          1024          16384 java.lang.ref.ReferenceQueue$Lock
----------------------------------------------
Total:                     1589848  (97 bytes/entry)


ClassValueMap is a WeakHashMap subclass which contains an array of 
WeakHashMap$Entry objects. In addition it maintains a parallel "cache" 
array of ClassValue$Entry objects. Both of those entry objects are 
WeakReferences. It means that each (Class,ClassValue) pair needs 2 
WeakReferences (with additional fields) and 2 array slots to hold 
associated value.

So I wondered, would it be possible to simplify CV and make it more 
straight-forward by taking away almost half of overhead to get this:

  num     #instances         #bytes  class name
----------------------------------------------
    1:         16384         655360 java.lang.ClassValue$Entry
    7:          1024         147456 [Ljava.lang.ClassValue$Entry;
   13:          1024          40960 java.lang.ClassValue$ClassValueMap
   15:          1024          32768 java.lang.ref.ReferenceQueue
   19:          1024          16384 java.lang.ref.ReferenceQueue$Lock
----------------------------------------------
Total:                      892928  (54 bytes/entry)


I tried and came up with the following:

http://cr.openjdk.java.net/~plevart/misc/ClassValue.Alternative/webrev.01/

It was not easy to keep the performance approximately on the same level 
while re-designing the implementation. But I think I managed to get it 
to perform mostly the same for the fast-path case. This alternative 
implementation also guarantees that, unless remove() is used, 
computeValue() is called exactly once per (Class, ClassValue) pair. 
Original implementation explains that it can redundantly compute more 
than one value and then throw away all but one. This alternative 
implementation could easily be modified to do the same (using CAS 
instead of lock) if anyone is afraid of deadlocks.

Here's a micro benchmark with results measuring original vs. alternative 
implementation. Attached results are for JDK9 on Intel i7 / Linux box 
using 4 concurrent threads for tests:

http://cr.openjdk.java.net/~plevart/misc/ClassValue.Alternative/ClassValueBench.java


It would be interesting to see if and how it works for you too (just 
compile and prepend to bootclasspath).

Regards, Peter

On 04/30/2015 03:57 PM, Michael Haupt wrote:
> Hi,
>
> I'm looking at JDK-8031043 and would appreciate if you guys could send 
> any code you think might benefit from a smaller initial CV memory 
> footprint my way. Given what I've read, it could have some impact 
> during startup (Groovy?) if the value is reduced to 1.
>
> Best,
>
> Michael
>
>> Am 30.04.2015 um 15:43 schrieb Charles Oliver Nutter 
>> <headius at headius.com <mailto:headius at headius.com>>:
>>
>> On Mon, Apr 27, 2015 at 12:50 PM, Jochen Theodorou <blackdrag at gmx.org 
>> <mailto:blackdrag at gmx.org>> wrote:
>>> Am 27.04.2015 19:17, schrieb Charles Oliver Nutter:
>>>> Jochen: Is your class-to-metaclass map usable apart from the Groovy
>>>> codebase?
>>>
>>>
>>> Yes. Look for 
>>> org.codehaus.groovy.reflection.GroovyClassValuePreJava7 which
>>> is normally wrapped by a factory.
>>
>> Excellent, thank you!
>>
>> - Charlie
>
>
> -- 
>
> Oracle <http://www.oracle.com/>
> Dr. Michael Haupt | Principal Member of Technical Staff
> Phone: +49 331 200 7277 | Fax: +49 331 200 7561
> OracleJava Platform Group | HotSpot Compiler Team
> Oracle Deutschland B.V. & Co. KG, Schiffbauergasse 14 | 14467 Potsdam, 
> Germany
> Green Oracle <http://www.oracle.com/commitment> 	Oracle is committed 
> to developing practices and products that help protect the environment
>
>
>
>
> _______________________________________________
> mlvm-dev mailing list
> mlvm-dev at openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20150503/25188b20/attachment.html>


More information about the mlvm-dev mailing list