Hi Peter,
computeValue() may recursively call get() by example to crawle the inheritance hierarchy so i am not sure a lock is a good idea here because in that case, it usually takes several millis to complete the to level computeValue.

regards,
RĂ©mi

On 05/03/2015 12:32 AM, Peter Levart wrote:
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 <head...@headius.com <mailto:head...@headius.com>>:

On Mon, Apr 27, 2015 at 12:50 PM, Jochen Theodorou <blackd...@gmx.org <mailto:blackd...@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@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev



_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to