Proxy.[isProxyClass|getProxyClass] scalability

Peter Levart peter.levart at gmail.com
Sun Jan 27 13:32:56 UTC 2013


Hi Alan, David,

I think I have a solution for scalability problems of 
java.lang.reflect.Proxy:

* http://dl.dropbox.com/u/101777488/jdk8-tl/proxy/webrev.01/index.html

I designed it along the lines mentioned in previous mail (see below). 
First I thought that both caches (a cache mapping request parameters of 
Proxy.getProxyClass to a proxy Class and a cache for resolving the 
Proxy.isProxyClass method) could be placed inside the j.l.ClassLoader. 
And they actually could. I tried this and it worked correctly, but the 
raw (single-threaded) performance of Proxy.isProxyClass was half the 
performance of current JDK8 isProxyClass method that way. The main 
performance hog I identified was the Class.getClassLoader() method. This 
method delegates to a native JVM method after checking the callers 
permissions. So the plan to keep the isProxyClass cache inside the 
ClassLoader failed. But then the ClassValue solution that I proposed in 
previous revision works beautifully and fast, so I kept this solution 
for isProxyClass cache. The ThreadLocal trick to initialize the 
ClassValue for a particular proxy class is necessary because ClassValue 
does not have a put() method. It does have actually, but it's package 
private and the comment suggests that it might not be there forever:

     // Possible functionality for JSR 292 MR 1
     /*public*/ void put(Class<?> type, T value) {
         ClassValueMap map = getMap(type);
         map.changeEntry(this, value);
     }

I could use the JavaLangAccess to access it from Proxy code though, so 
this is another refinement that is possible and would eliminate the need 
for ThreadLocal trick.
The cache for getProxyClass method on the other hand is most naturally 
hosted by j.l.ClassLoader and that's where I put it in the proposed 
patch. Currently the cross-package access to it is implemented using 
Unsafe, but the performance aspect is not so critical that It couldn't 
be changed to using JavaLangAccess instead if desired.
I did some performance testing too. Here are the results taken on 3 
different systems (i7 Linux PC, Raspberry Pi and Sun-Blade-T6320 Solaris 
machine):

* 
https://raw.github.com/plevart/jdk8-tl/proxy/test/proxy_benchmark_results.txt

These are the test sources i used:

* 
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

Results show scalability and raw performance improvements for both 
critical Proxy methods.

So what do you think?


Regards, Peter


On 01/25/2013 06:55 PM, Peter Levart wrote:
> On 01/24/2013 03:34 PM, Peter Levart wrote:
>> On 01/24/2013 03:10 PM, Alan Bateman wrote:
>>> On 24/01/2013 13:49, Peter Levart wrote:
>>>> Should I file a RFE first?
>>> Sorry I don't have time at the moment to study the proposed patch 
>>> but just to mention that it has come up a few times, its just that 
>>> it never bubbled up to the top of anyone's list. Here's the bug 
>>> tracking it:
>>>
>>> http://bugs.sun.com/view_bug.do?bug_id=7123493
>>>
>>> -Alan.
>> I belive that is another bottleneck. It is mentioning the 
>> Proxy.getProxyClass method which also uses synchronization for 
>> maintaining a cache of proxy classes by request parameters. I could 
>> as well try to fix this too in the same patch if there is interest.
>>
>> Regards, Peter
>>
>
> Hi Alan, David,
>
> I thought about the ways to fix Proxy.isProxyClass() scalability and 
> the Proxy.getProxyClass() scalability. While they are different 
> methods, each with it's own data structure, I think that both problems 
> can be solved with a single solution and that solution does not 
> involve neither adding fields to j.l.Class nor ClassValue.
>
> The solution is actually very simple. I just want to validate my 
> reasoning before jumping to implement it:
>
> - for solving scalability of getProxyClass cache, a field with a 
> reference to ConcurrentHashMap<List<String>, Class<? extends Proxy>> 
> is added to j.l.ClassLoader
> - for solving scalability of isProxyClass, a field with a reference to 
> ConcurrentHashMap<Class<? extends Proxy>, Boolean> is added to 
> j.l.ClassLoader
>
> Both maps hold strong references to Class objects, but only for the 
> classes that are loaded by the ClassLoader that references them. Each 
> ClassLoader already holds a strong reference to all the Class objects 
> for the classes that were loaded by it in a Vector. Holding another 
> reference does not present any problem, right?
>
> I think this would be the best solution and it would solve both 
> scalability problems of j.l.Proxy in one go.
>
> Am I missing something?
>
> Regards, Peter
>




More information about the core-libs-dev mailing list