Proxy.isProxyClass scalability
Peter Levart
peter.levart at gmail.com
Mon Jan 28 16:13:11 UTC 2013
Hi Alan,
I prepared the variant with lazy initialization of ConcurrentHashMaps
per ClassLoader and performance measurements show no differences. So
here's this variant:
* http://dl.dropbox.com/u/101777488/jdk8-tl/proxy/webrev.03/index.html
I also checked the ClassLoader layout and as it happens the additional
pointer slot increases the ClassLoader object size by 8 bytes in both
addressing modes: 32bit and 64bit. But that's a small overhead compared
to for example the deep-size of AppClassLoader at the beginning of the
main method: 14648 bytes (32bit) / 22432 bytes (64bit).
Regards, Peter
On 01/28/2013 01:57 PM, Peter Levart wrote:
> On 01/28/2013 12:49 PM, Alan Bateman wrote:
>> On 25/01/2013 17:55, Peter Levart wrote:
>>>
>>> :
>>>
>>> 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
>> I haven't had time to look very closely as your more recent changes
>> (you are clearly doing very good work here). The only thing I wonder
>> if whether it would be possible to avoid adding to ClassLoader. I
>> can't say what percentage of frameworks and applications use proxies
>> but it would be nice if the impact on applications that don't use
>> proxies is zero.
> Hi Alan,
>
> Hm, well. Any application that uses run-time annotations, is
> implicitly using Proxies. But I agree that there are applications that
> don't use either. Such applications usually don't use many
> ClassLoaders either. Applications that use many ClassLoaders are
> typically application servers or applications written for modular
> systems (such as OSGI or NetBeans) and all those applications are also
> full of runtime annotations nowadays. So a typical application that
> does not use neither Proxies nor runtime annotations is composed of
> bootstrap classloader, AppClassLoader and ExtClassLoader. The
> ConcurrentHashMap for the bootstrap classloader is hosted by
> j.l.r.Proxy class and is only initialized when the j.l.r.Proxy class
> is initialized - so in this case never. The overhead for such
> applications is therefore an empty ConcurrentHashMap instance plus the
> overhead for a pointer slot in the ClassLoader object multiplied by
> the number of ClassLoaders (typically 2). An empty ConcurrentHashMap
> in JDK8 is only pre-allocating a single internal Segment:
>
> java.util.concurrent.ConcurrentHashMap at 642b6fc7(48 bytes) {
> keySet: null
> values: null
> hashSeed: int
> segmentMask: int
> segmentShift: int
> segments:
> java.util.concurrent.ConcurrentHashMap$Segment[16]@8e1dfb1(80 bytes) {
> java.util.concurrent.ConcurrentHashMap$Segment at 2524e205(40 bytes) {
> sync:
> java.util.concurrent.locks.ReentrantLock$NonfairSync at 17feafba(32 bytes) {
> exclusiveOwnerThread: null
> head: null
> tail: null
> state: int
> }->(32 deep bytes)
> table:
> java.util.concurrent.ConcurrentHashMap$HashEntry[2]@1c3aacb4(24 bytes) {
> null
> null
> }->(24 deep bytes)
> count: int
> modCount: int
> threshold: int
> loadFactor: float
> }->(96 deep bytes)
> null
> null
> null
> null
> null
> null
> null
> null
> null
> null
> null
> null
> null
> null
> null
> }->(176 deep bytes)
> keySet: null
> entrySet: null
> values: null
> }->(224 deep bytes)
>
> ...therefore the overhead is approx. 224+4 = 228 bytes (on 32 bit
> pointer environments) per ClassLoader. In typical application (with 2
> ClassLoader objects) this amounts to approx. 456 bytes.
>
> Is 456 bytes overhead too much?
>
> If it is, I could do lazy initialization of per-classloader CHM
> instances, but then the fast-path would incur a little additional
> penalty (not to be taken seriously though).
>
> Regards, Peter
>
> P.S. I was inspecting the ClassValue internal implementation. This is
> a very nice piece of Java code. Without using any Unsafe magic, it
> provides a perfect performant an scalable map of lazily initialized
> independent data structures associated with Class instances. There's
> nothing special about ClassValue/ClassValueMap that would tie it to
> Class instances. In fact I think the ClassValueMap could be made
> generic so it could be reused for implementing a ClasLoaderValue, for
> example. This would provide a more performant and scalable alternative
> to using WeakHashMap<ClassLoader, ...> wrapped by synchronized
> wrappers for other uses.
> If anything like that happens in the future, the proposed patch can be
> quickly adapted to using that infrastructure instead of a direct
> reference in the ClassLoader.
>
>>
>> -Alan
>
More information about the core-libs-dev
mailing list