Hi JC,

On Thu, Nov 8, 2018 at 5:49 PM JC Beyler <jcbey...@google.com> wrote:
>
> Hi Thomas,
>
> When I follow the code flow, yes that seems right; your comment " a caller 
> may hand it in long after the class has been unloaded, and this should be 
> handled gracefully" is exactly what the spec says for example for a lot of 
> the JVMTI methods that take a methodId such as SetBreakpoint[1] for example.

Oh right. I was struggling to find a good example for why we cannot
let jmethodids expire. But sure, the debugger could have set there for
an hour after calling GetClassMethods, and the jmethodids could be all
stale.

>
> Doing it this way is the easiest (safest?) way to ensure that if a class is 
> unloaded, there is a means to be passing invalid method ids to JVMTI methods 
> without having everything break or having to have in memory what methods are 
> still valid.

Its also quite cheap. We pay 8 bytes of leaked memory per jmethodid,
plus a bit of overhead. I struggle to come up with a better scheme. I
guess one could, with some sort of offset based addressing, trim this
down to 32bit? Or some magic with un-committing the underlying memory
under the JNIMethodBlockNodes but keeping the address space reserved,
and then catching the segfault with SafeFetch. But I do not know if it
would be worth the effort.

> [1] 
> https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html#SetBreakpoint
>
> Or more in detail, a lot of JVMTI methods have a nice:
>   NULL_CHECK(method_oop, JVMTI_ERROR_INVALID_METHODID);
>
> That allows to do this check and, so technically, the comment could be 
> amended to say "JVMTI also is expecting this".
>
I agree.

> Is there a real case where this leak is becoming noticeable?
>

Yes, we have this client which uses our VM in weird and intricate
ways. Embedded in an own launcher, lots of JNI coding. They seem to be
doing just that: over and over reloading classes in new class loaders
and accessing them via JNI. Last I saw they allocated 250 MB worth of
JNIMethodBlockNodes, which would amount to roughly 3 million jmethodid
handles...

> Thanks,
> Jc
>

Thanks for looking!

Best Regards, Thomas

>
>
> On Thu, Nov 8, 2018 at 12:02 AM Thomas Stüfe <thomas.stu...@gmail.com> wrote:
>>
>> .. moving to serviceability - maybe you can help me.
>>
>> Thanks! Thomas
>>
>>
>> ---------- Forwarded message ---------
>> From: Thomas Stüfe <thomas.stu...@gmail.com>
>> Date: Wed, Nov 7, 2018, 11:38
>> Subject: JNIMethodBlockNode leak question
>> To: Hotspot dev runtime <hotspot-runtime-...@openjdk.java.net>
>>
>>
>> Hi all,
>>
>> I wonder whether I understand this correctly:
>>
>> When a caller requests a jmethodId bei either calling
>> jni-GetMethodId() or jvmti-GetClassMethods(), the returned jmethodId
>> is a pointer into a slot of a table containing the respective Method*
>> pointers. That table is tied to the ClassLoaderData. When the
>> classloader is unloaded and its ClassLoaderData deleted, we do not
>> delete that table, but rather deliberately leak it after zeroing it
>> out. The reason - if I understand the comment in ~ClassLoaderData
>> correctly - is that jmethodId live forever - a caller may hand it in
>> long after the class has been unloaded, and this should be handled
>> gracefully.
>>
>> We cannot simply delete its JNIMethodBlockNode, since the jmethodId
>> then would either point to unmapped memory - which we could handle
>> with SafeFetch - but worse could point to memory reused for a
>> different purpose.
>>
>> We also could not reuse that slot, since then that jmethodId would
>> point to a different method? Apart from the fact that we would need
>> infrastructure for that, a global pool of JNIMethodBlockNode, with
>> associated locking etc.
>>
>> Have I understood this correctly or am I off somewhere?
>>
>> And if I am right, that would mean that were we to generate classes
>> over and over again in new class loaders and accessing their methods
>> with JNI, we would have a slowly growing leak, even if we clean up the
>> loaders?
>>
>> Thanks, Thomas
>
>
>
> --
>
> Thanks,
> Jc

Reply via email to