Proxy.isProxyClass scalability
Peter Levart
peter.levart at gmail.com
Mon Jan 28 12:57:44 UTC 2013
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