JNI - question about jmethodid values.

Thomas Stüfe thomas.stuefe at gmail.com
Sat Nov 24 15:41:18 UTC 2018


Hi Peter,

(adding serviceability)

A jmethodid is a pointer to malloc'ed memory.

In more detail, jmethodid points to a table slot containing pointers
to Method* objects, and that table itself lives in C heap. See class
JNIMethodBlock, JNIMethodBlockNode:
http://hg.openjdk.java.net/jdk/jdk/file/30a02b4e6c06/src/hotspot/share/oops/method.cpp#l1928

If I understand the NetBeans profiler coding right, they assume the
jmethodIDs to cluster in up to four clusters of relative vicinity,
with each cluster spanning 30 bits? That is quite an assumption to
make.

This may work more or less accidentally, since malloc'ed pointers are
also clustered naturally. A Clib implementation may allocate only in
the traditional data segment (below sbrk) - I believe AIX and Solaris
do this - which means all malloced pointers are as close to each other
as the data segment is large. But C-Libraries often allocate C-Heap
memory in separate mmape'd blocks (e.g. glibc arenas), and there is no
guarantee where those blocks are. You may still often get lucky - if
all jmethod id block allocations happen in a short timeframe, or if
you just have not many users of C-Heap in the process.

But it is not guaranteed to work. I would probably rather use a
hashmap or similar.

Side note: I believe (and someone please correct me if I am wrong)
that jmethodid used to live in the PermGen, in the Java Heap, and that
only since the PermGen removal in JDK8 they live in C-Heap. If this is
true, this 4x30bit assumption may actually have worked before jdk8,
since the java heap is allocated as one continuous space, with the
PermGen clustered in one part of it.

Best Regards, Thomas


On Sat, Nov 24, 2018 at 3:51 PM Peter Hull <peterhull90 at gmail.com> wrote:
>
> I have recently been looking at some native code that's part of the
> NetBeans profiler. This code was crashing for me because it was based
> on incorrect assumptions about the sizes of various primitive types.
> There is some code which is intended to map jmethodid values to jint
> values (see below). This is trivial on 32 bit platforms because the
> are the same size. However on 64-bit platforms this is not the case
> because jmethodid is (according to the docs) to be treated as a
> pointer to an opaque structure and is 64-bit.
> So, the code splits the 64-bit jmethodid into a 30-bit 'offset' part
> and a 34-bit 'base' part. It then stores the high part in one of four
> slots and returns a 32 bit int which is 2 bits for the slot id and 30
> bits from the offset part. For the reverse process, it looks up the
> slot id, gets the base address and ORs it with the offset. This seems
> to work in practice but it is based on the assumption that all
> jmethodids will have one of only four base parts - any more than four
> can't be specified by a 2 bit id.
> So my question is: is this a sound assumption? The answer needs some
> detailed knowledge of the internals of the JRE I suppose, so if this
> mailing list is not the right place to ask, what is the right place?
> I want to fix my crash in the netbeans profiler but I want to do the
> right thing rather than just patching it up (which I have done by
> doing casts more carefully)
> Thanks for your help.
> Peter
>
> For reference, the code is on github:
> https://github.com/apache/incubator-netbeans/blob/5405b8c93eeafdd213cffcc59df002464af8d838/profiler/lib.profiler/native/src-jdk15/Stacks.c#L66-L92
> and: https://github.com/apache/incubator-netbeans/blob/5405b8c93eeafdd213cffcc59df002464af8d838/profiler/lib.profiler/native/src-jdk15/Stacks.c#L66-L92


More information about the discuss mailing list