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