ClassLoader leak in MethodHandle.asType()

Peter Levart peter.levart at gmail.com
Fri Apr 24 22:24:27 UTC 2015


On 04/24/2015 11:06 PM, John Rose wrote:
> Good point.  Are you seeing a leak in practice?
> The cache is important, especially to inexact MH.invoke.
> — John

Well, yes. I am (re)implementing annotations (proxies) using Remi's 
Proxy2 and made it all the way except for the following failing jtreg test:

jdk/test/java/lang/annotation/loaderLeak/Main.java

...which made me find this issue. What I'm doing is the following:

For implementing some annotation @Ann proxy's hashCode() method for 
example, I prepare DMHs with the following signature (T)int for Ts being 
all primitives, primitive arrays, Object[] and Object. I cache them in a 
system class static field referenced HashMap keyed by Class<T>. These 
are the functions that take an annotation member value and map it to 
it's hashCode. When the value is of some Object (or Object[] in case it 
is an array) subtype - for example when the member value is an 
annotation of type V, I take the (Object)int DMH and transform it with 
.asType(methodType(int.class, V.class)) to get (V)int, which is 
necessary to further wrap it with filterArguments where the filter is a 
member field getter of type (Ann)V so that I get (Ann)int MHs as a kind 
of hashCodeExtractors for all annotation members (I'll present the 
details later)...

Now if V is an annotation type that is loaded by a child class loader, 
it gets retained by system cached DMH.

But now that I'm writing this, I see a workarround. Instead of 
transforming hashCode function (Object)int -> (V)int and applying field 
getter (Ann)V as an argument filter, I could transform the field getter 
argument filter (Ann)V -> (Ann)Object and apply it directly to the 
argument of hashCode function (Object)int.

Anyway. The inexact invoke() always transforms a specific MH to a 
generic one (Object, Object, ...)Object, right? So using inexact 
invoke() on any MH can't trigger the leak. It's just that if someone 
attempts to transform a generic MH to some more concrete one to be able 
to "connect" it with further transformations does the danger of the leak 
appear. So maybe, just for the purpose of inexact invoke(), the caching 
could be performed just in case when asType transformed method type is 
of the form (Object, Object, ...)Object. This would also prevent 
accidental thrashing of the cache when inexact invoke() is intermixed 
with other asType() invocations.

Regards, Peter

>
> On Apr 24, 2015, at 9:14 AM, Peter Levart <peter.levart at gmail.com 
> <mailto:peter.levart at gmail.com>> wrote:
>>
>> I think there is a Class(Loader) leak in MethodHandle.asType() 
>> implementation. If for example some MH (say mhX) is long lived 
>> (because it is a system cached MH) and a client "generates" variants 
>> from it by invoking mhX.asType(newType) and the newType contains a 
>> type (either return type or parameter type) that is loaded by some 
>> child ClassLoader, then such derived MH is retained strongly from mhX 
>> via the MethodHandle.asTypeCache field. Until this field is 
>> overwriten by some other MH, child ClassLoader can not be GCed.
>>
>> In case this one-element cache is needed to speed things up, it 
>> should be a WeakReference, like the following:
>>
>> http://cr.openjdk.java.net/~plevart/jdk9-dev/MethodHandle.asTypeCacheLeak/webrev.01/ 
>> <http://cr.openjdk.java.net/%7Eplevart/jdk9-dev/MethodHandle.asTypeCacheLeak/webrev.01/>
>>
>
>
>
> _______________________________________________
> mlvm-dev mailing list
> mlvm-dev at openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/mlvm-dev/attachments/20150425/19d2fc89/attachment.html>


More information about the mlvm-dev mailing list