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


Reply via email to