Proxy.isProxyClass scalability

Peter Levart peter.levart at
Wed Apr 24 07:13:31 UTC 2013

On 04/24/2013 07:33 AM, Mandy Chung wrote:
> More comments in addition to what I replied earlier....
> On 4/23/2013 4:43 PM, Mandy Chung wrote:
>>> Each ClassLoader maintains explicit hard-references to all Class 
>>> objects for classes defined by the loader. So proxy Class object can 
>>> not be GC-ed until the ClassLoader is GC-ed. 
> AFAIU, a class loader will be GC'ed as long as there is no reference 
> to any of its loaded classes.  The ClassLoader's internal vector of 
> keeping the loaded classes is to prevent the classes from being GC'ed 
> until the class loader is being GC'ed which will unload the classes.
> So we should make the class loader and the proxy classes weak 
> referenced so that they will be GC'ed properly.

That's right.

>>> So we need not register the CacheValue objects in WeakCache with a 
>>> refQueue. The expunging of reverseMap entries is already performed 
>>> with CacheKey when it is cleared and equeued. There's no harm as it 
>>> is, since the clean-up is performed with all the checks and is 
>>> idempotent, but it need not be done for ClassValue objects holding 
>>> weak references to proxy Class objects.
> I actually think we don't need to make CacheKey as a weak reference 
> but the CacheValue object should still be registered in the refQueue.  
> The proxy class in the CacheValue implementing the given interfaces 
> always reference the interfaces in the CacheKey and it means that the 
> classes in the CacheKey will never be GC'ed before the proxy class.   
> When there is no reference to the proxy class, it will be added to the 
> reference queue.  Once the entry with the CacheValue holding the proxy 
> class is expunged,  the interfaces will not be referenced in the cache.

But! If the interface in the sub-key (the CacheKey in WeakCache is the 
1st-level key and is a WeakReference<ClassLoader>, the sub-key holds 
interfaces or interface names) happens to be loaded by the same 
ClassLoader as the proxy class, the ClassLoader will never be GC-ed and 
consequently the ClassValue will never be cleared and the entry will 
never be expunged... We have to wrap with a WeakReference:
- the ClassLoader
- each individual interface Class object
- proxy Class object

All 3 types of objects can have implicit or explicit strong references 
among them.

Regards, Peter

> Does this make sense to you?
> Mandy
>> As explained above, for the per-loader proxy class cache, both the 
>> key (interfaces) and the proxy class should be wrapped with weak 
>> reference.
>> In your revisions, you optimize for 0-interface and 1-interface proxy 
>> class.  What I hacked up earlier was just to use Class<?>[] as the 
>> key (need to make a copy of the array to prevent that being mutated 
>> during runtime) that is a simpler and straightforward 
>> implementation.  I didn't measure the footprint and compare the 
>> performance of your versions.  Have you seen any performance 
>> difference which led you to make the recent changes?
>> Mandy
>> [1] 

More information about the core-libs-dev mailing list