United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-7123493 : (proxy) Proxy.getProxyClass doesn't scale under high load

Details
Type:
Bug
Submit Date:
2011-12-21
Status:
Closed
Updated Date:
2014-04-24
Project Name:
JDK
Resolved Date:
2013-04-26
Component:
core-libs
OS:
linux
Sub-Component:
java.lang:reflect
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
7
Fixed Versions:

Related Reports
Backport:
Backport:
Backport:
Duplicate:
Duplicate:
Relates:

Sub Tasks

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 



                                     
2013-04-26
URL:   http://hg.openjdk.java.net/jdk8/tl/jdk/rev/5e7ae178b24d
User:  mchung
Date:  2013-04-26 23:09:52 +0000

                                     
2013-04-26
URL:   http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/5e7ae178b24d
User:  lana
Date:  2013-05-07 18:40:01 +0000

                                     
2013-05-07



Hardware and Software, Engineered to Work Together