JDK-7123493 : (proxy) Proxy.getProxyClass doesn't scale under high load
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2011-12-21
  • Updated: 2015-04-17
  • Resolved: 2013-04-26
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 JDK 8
6u71Fixed 7u60Fixed 8 b89Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
This has been  a production critical problem since October 2007.

It is still a problem in:

java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Server VM (build 21.0-b17, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
2.6.38-gentoo-r5 #1 SMP PREEMPT Wed May 11 20:18:51 UTC 2011 x86_64 Intel(R) Core(TM) i7 CPU Q 820 @ 1.73GHz GenuineIntel GNU/Linux

A DESCRIPTION OF THE PROBLEM :
The Proxy class has poor performance under multi-threaded environments

http://sesat.no/projects/sesat-commons/commons-reflect/
 has a ConcurrentProxy implementation that is basically a copy of Proxy but
changes the caching mechanism from using a HashMap surrounded with hard synchronization to a ConcurrentMap.

This has been used intensely, and was a necessity, in production at
http://sesam.no
http://sesam.se
http://finn.no

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Use Proxy.getProxyClass(..) under very high concurrency.

(It's rather obvious that any HashMap+synchronised-block will lock up under high concurrency).

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Decent performance under high concurrency.
ACTUAL -
Poor performance, or complete lock up of the jvm.

REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
Replace all occurrences of Proxy with ConcurrentProxy from the project "commons-reflection" hosted at https://github.com/finn-no/commons-reflection
See:  https://bugs.openjdk.java.net/show_bug.cgi?id=100120
Copied from http://bugs.openjdk.java.net/show_bug.cgi?id=100120
Description From Mck 2009-11-09 04:46:47 PDT

The Proxy class has poor performance under multi-threaded environments

http://sesat.no/projects/sesat-commons/commons-reflect/ 
 has a ConcurrentProxy implementation that is basically a copy of Proxy but
changes the caching mechanism from using a Hashtable to a ConcurrentMap.

This has been used intensely, and was a necessity, in production at
http://sesam.no & http://sesam.se

Comment #1 From Mck 2009-11-09 04:48:30 PDT

Patch (file) in the url field

Comment #2 From Mck 2011-12-21 00:30:59 PDT

>  has a ConcurrentProxy implementation that is basically a copy of Proxy but
> changes the caching mechanism from using a Hashtable to a ConcurrentMap.
> 

Correction: It's a HashMap with synchronized statements that are being replaced
with a ConcurrentMap.

Comment #3 From ###@###.### 2011-12-21 00:46:24 PDT

I would suggest bringing this up on ###@###.### for
discussion.

Comment #4 From Mck 2011-12-21 01:49:25 PDT

code now hosted at https://github.com/finn-no/commons-reflection

Comment #5 From Mck 2011-12-22 04:09:53 PDT

cross-reference: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7123493

i subscribed to core-libs-dev and posted but it doesn't look like it's getting
through.

Comment #6 From rogerl 2011-12-30 14:09:37 PDT

(In reply to comment #5)
> cross-reference: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7123493
> 
> i subscribed to core-libs-dev and posted but it doesn't look like it's getting
> through.

Ensure that you have completed the registration, following the instructions in
the email sent shorty after you registered. Also, you may need to send mail to
the alias in plain text, it has been seen that sending mail in HTML will
prevent the mail from being accepted. 

-Roger

Comment #7 From Tim Bell 2012-07-06 17:01:58 PDT

Closing.  This is SUNBUG 7123493

Comments
Nice contribution from Peter Levart. Replace the WeakHashMap with ConcurrentHashMap and also define a ProxyClassFactory as a Supplier as a clean way to handle multiple requests in generating a proxy class for the same class loader and same set of interfaces. Below shows the result of the microbenchmark: https://github.com/plevart/jdk8-tl/blob/proxy/test/src/test/ProxyBenchmarkTest.java https://github.com/plevart/micro-bench/blob/master/src/si/pele/microbench/TestRunner.java jdk8 b86: ############################################################## # OS: Mac OS X 10.7.5 (x86_64) # CPUs: 8 (virtual) # #------------------------------------------------------------- # Proxy_getProxyClass: run duration: 5,000 ms # # Warm up: # 1 threads, Tavg = 5,719.67 ns/op # 1 threads, Tavg = 5,430.75 ns/op # Measure: 1 threads, Tavg = 5,435.06 ns/op 2 threads, Tavg = 6,336.01 ns/op 3 threads, Tavg = 6,923.37 ns/op 4 threads, Tavg = 7,904.96 ns/op 5 threads, Tavg = 9,576.69 ns/op 6 threads, Tavg = 11,355.99 ns/op 7 threads, Tavg = 13,048.70 ns/op 8 threads, Tavg = 14,984.02 ns/op # #------------------------------------------------------------- # Proxy_isProxyClassTrue: run duration: 5,000 ms # # Warm up: # 1 threads, Tavg = 156.38 ns/op # 1 threads, Tavg = 156.25 ns/op # Measure: 1 threads, Tavg = 157.27 ns/op 2 threads, Tavg = 1,037.68 ns/op 3 threads, Tavg = 1,060.80 ns/op 4 threads, Tavg = 1,389.96 ns/op 5 threads, Tavg = 1,826.51 ns/op 6 threads, Tavg = 2,313.36 ns/op 7 threads, Tavg = 2,755.44 ns/op 8 threads, Tavg = 3,158.77 ns/op # #------------------------------------------------------------- # Proxy_isProxyClassFalse: run duration: 5,000 ms # # Warm up: # 1 threads, Tavg = 108.75 ns/op # 1 threads, Tavg = 104.18 ns/op # Measure: 1 threads, Tavg = 149.65 ns/op 2 threads, Tavg = 833.12 ns/op 3 threads, Tavg = 937.14 ns/op 4 threads, Tavg = 1,410.67 ns/op 5 threads, Tavg = 1,708.30 ns/op 6 threads, Tavg = 2,078.31 ns/op 7 threads, Tavg = 2,261.50 ns/op 8 threads, Tavg = 2,780.04 ns/op # #------------------------------------------------------------- # Annotation_equals: run duration: 5,000 ms # # Warm up: # 1 threads, Tavg = 389.43 ns/op # 1 threads, Tavg = 382.63 ns/op # Measure: 1 threads, Tavg = 371.72 ns/op 2 threads, Tavg = 1,288.23 ns/op 3 threads, Tavg = 1,849.06 ns/op 4 threads, Tavg = 3,153.15 ns/op 5 threads, Tavg = 4,054.31 ns/op 6 threads, Tavg = 4,926.69 ns/op 7 threads, Tavg = 5,717.96 ns/op 8 threads, Tavg = 6,476.88 ns/op jdk8 + with this fix yields significant performance improvement: ############################################################## # OS: Mac OS X 10.7.5 (x86_64) # CPUs: 8 (virtual) # #------------------------------------------------------------- # Proxy_getProxyClass: run duration: 5,000 ms # # Warm up: # 1 threads, Tavg = 278.01 ns/op # 1 threads, Tavg = 258.62 ns/op # Measure: 1 threads, Tavg = 264.07 ns/op 2 threads, Tavg = 281.88 ns/op 3 threads, Tavg = 369.47 ns/op 4 threads, Tavg = 357.82 ns/op 5 threads, Tavg = 514.52 ns/op 6 threads, Tavg = 505.23 ns/op 7 threads, Tavg = 578.44 ns/op 8 threads, Tavg = 634.17 ns/op # #------------------------------------------------------------- # Proxy_isProxyClassTrue: run duration: 5,000 ms # # Warm up: # 1 threads, Tavg = 89.03 ns/op # 1 threads, Tavg = 88.02 ns/op # Measure: 1 threads, Tavg = 87.66 ns/op 2 threads, Tavg = 90.71 ns/op 3 threads, Tavg = 96.10 ns/op 4 threads, Tavg = 106.06 ns/op 5 threads, Tavg = 126.57 ns/op 6 threads, Tavg = 143.16 ns/op 7 threads, Tavg = 160.78 ns/op 8 threads, Tavg = 180.13 ns/op # #------------------------------------------------------------- # Proxy_isProxyClassFalse: run duration: 5,000 ms # # Warm up: # 1 threads, Tavg = 20.44 ns/op # 1 threads, Tavg = 20.26 ns/op # Measure: 1 threads, Tavg = 20.63 ns/op 2 threads, Tavg = 21.33 ns/op 3 threads, Tavg = 22.55 ns/op 4 threads, Tavg = 27.12 ns/op 5 threads, Tavg = 32.73 ns/op 6 threads, Tavg = 36.65 ns/op 7 threads, Tavg = 40.60 ns/op 8 threads, Tavg = 45.03 ns/op # #------------------------------------------------------------- # Annotation_equals: run duration: 5,000 ms # # Warm up: # 1 threads, Tavg = 308.54 ns/op # 1 threads, Tavg = 303.96 ns/op # Measure: 1 threads, Tavg = 305.63 ns/op 2 threads, Tavg = 319.34 ns/op 3 threads, Tavg = 344.70 ns/op 4 threads, Tavg = 390.69 ns/op 5 threads, Tavg = 473.32 ns/op 6 threads, Tavg = 558.68 ns/op 7 threads, Tavg = 615.92 ns/op 8 threads, Tavg = 689.75 ns/op
26-04-2013