Clarification on what the JNI spec means by nonmovable

David Holmes david.holmes at
Thu Sep 8 22:11:28 UTC 2016

On 9/09/2016 7:21 AM, Jon V. wrote:
> Krystal,
> re
> Thanks for clearing up that Critical sections can be nested.  “We must
> treat the code inside this pair of functions as running in a "critical
> region." Inside a critical region, native code must not call other JNI
> functions,” wasn’t terribly clear and the code example doesn’t appear
> everywhere.
> The code example here:
>  jint len = (*env)->GetArrayLength(env, arr1);
>   jbyte *a1 = (*env)->GetPrimitiveArrayCritical(env, arr1, 0);
>   jbyte *a2 = (*env)->GetPrimitiveArrayCritical(env, arr2, 0);
>   /* We need to check in case the VM tried to make a copy. */
>   if (a1 == NULL || a2 == NULL) {
>     ... /* out of memory exception thrown */
>   }
>   memcpy(a1, a2, len);
>   (*env)->ReleasePrimitiveArrayCritical(env, arr2, a2, 0);
>   (*env)->ReleasePrimitiveArrayCritical(env, arr1, a1, 0);
> Looks unsafe because it would be possible to acquire a1 then not acquire a2
> whereas throwing an exception and exiting the method would keep the lock on
> a1.

"throwing an exception" here means to establish a pending exception that 
will be thrown when you return to Java code. Unless you code it into the 
if-block there is no transfer of control that will skip the Release* 
calls. The example is still not great though - not sure what happens if 
you try to release something you didn't acquire.


> On Thu, Sep 8, 2016 at 2:53 PM, Krystal Mok <rednaxelafx at> wrote:
>> On Thu, Sep 8, 2016 at 10:42 AM, Jon V. <sybersnake at> wrote:
>>> Thank you Kris.
>>> That confirms my understanding that the indirect pointers can be moved at
>>> anytime.  I’m accessing possible multiple heap objects inside of a single
>>> JNI call and you aren’t allowed to call critical sections twice.
>> Wait... a JNI critical section isn't like a OS thread-synchronization
>> critical section. It does support nesting. What is the access pattern
>> you're looking at?
>> c.f.
>> guides/jni/spec/functions.html#GetPrimitiveArrayCritical
>>> Multiple pairs of GetPrimtiveArrayCritical and
>> ReleasePrimitiveArrayCritical may be nested.
>>> I’ve created a workaround of using getCrtiicalString as a way to stop GC
>>> then directly access the heap memory of the other objects.  This seems like
>>> a safe way to do this.
>> Nope, the JNI API does not guarantee this to be safe. Doing this is
>> essentially cheating on JVMs such as HotSpot that implements JNI critical
>> sections via temporarily disabling the GC.
>> JNI critical section only guarantees "critical access" to the specified
>> object, and that doesn't necessarily extends to other objects.
>> JNI critical section may be implemented via "object pinning" support in
>> the VM. Pinning may happen at different granularities in different JVMs:
>> * on object level: only the specified object is pinned;
>> * on page / region level: all objects in the page or region in which the
>> specified object resides is pinned as a whole;
>> * on heap level: all objects in the whole GC heap is pinned.
>> Disabling moving GCs from running is effectively pinning on the heap
>> level. That's what HotSpot currently implements. But there's no guarantee
>> that it'll stay that way in the future.
>> JRockit, for example, supports object-level pinning. So
>> your GetStringCritical trick is likely to break if you ever try that on
>> JRockit.
>>> I really wish JNI had another wrapper/macro we could use such as
>>> JNI_QUICK_ENTRY that would prevent GC without having to use GCLocker.  Some
>>> way my JNI call could be considered “inVM” instead of “inNative” to keep GC
>>> at bay.
>>> I'll have to leave this one to the HotSpot GC folks...
>> - Kris
>>> On Thu, Sep 8, 2016 at 1:30 PM, Krystal Mok <rednaxelafx at>
>>> wrote:
>>>> Hi Jon,
>>>> On Thu, Sep 8, 2016 at 9:30 AM, Jon V. <sybersnake at> wrote:
>>>>> Hello everyone!
>>>>> I’m trying to document the exact behavior of direct pointer access of
>>>>> passed arguments into JNI in HotSpot.  I have a huge post on
>>>>> StackOverflow
>>>>> for posterity purposes as it seems to be a commonly misunderstood
>>>>> behavior.
>>>>> fe-access-of-jni-arguments
>>>>> from
>>>>> pec/design.html#wp16789
>>>>> The JNI spec says, “To implement local references, the Java VM creates a
>>>>> registry for each transition of control from Java to a native method. A
>>>>> registry maps nonmovable local references to Java objects, and keeps the
>>>>> objects from being garbage collected.”
>>>>> "Nonmovable" refers to the "local JNI reference", not the Java object
>>>> instance itself. What that gurantees is that, given a jobject (which is
>>>> typedef'd as an opaque pointer), you can safely say that as long as this
>>>> jobject is still in scope, the value of the jobject won't change. But that
>>>> doesn't imply anything related whether or not the Java object it's
>>>> referring to is pinned.
>>>> The "registry map" here is just an abstract notion that doesn't
>>>> necessarily materialize into any real data structures in some certain JVM
>>>> implementations.
>>>>> I’m trying to understand if “nonmovable” actually means that the
>>>>> objects in
>>>>> the map WILL NOT be compacted/moved (heap memory) or if it just means
>>>>> they
>>>>> won’t be garbage-collected.  The answer dictates if the use of critical
>>>>> sections are actually necessary.
>>>>> Rule of thumb: don't try to bypass the JNI abstractions. It'll bite
>>>> back hard if you switch between different JVM implementations.
>>>> Specifically in HotSpot, jobject and friends are referred to as "JNI
>>>> handles". That's because they're implemented as handles, i.e.
>>>> double-indirection pointers. The underlying type that implements jobject is
>>>> "oop*", where an "oop" is typedef'd from "oopDesc*", and oopDesc is the
>>>> root type of garbage collected objects.
>>>> jobject    JNIHandle   Java object
>>>> [ oop* ] -> [ oop ] -> [ oopDesc ]
>>>> Following the spec, what it guarantees is that for a given jobject, the
>>>> JNIHandle representing the referent object will not be moved, but the
>>>> actual referent object is free to move.
>>>> Don't try to access raw oops from outside the VM by accessing the
>>>> underlying handle internals. It's very likely to get dangling pointers
>>>> after GCs.
>>>> What are the effects for each garbage collector?
>>>>> All garbage collectors in HotSpot, except for CMS (mostly concurrent
>>>> mark-sweep), are moving collectors. As such, after each completed
>>>> collection, Java objects will move. If you're holding raw oops that the GC
>>>> isn't aware of, they won't be updated during GC, and will be left dangling
>>>> afterwards.
>>>> JNI critical sections are implemented in HotSpot via temporarily
>>>> disabling the GCs, and as soon as all JNI critical sections are completed,
>>>> a full GC (by default) will be triggered to perform the delayed collection
>>>> if needed. This mechanism is called the "GCLocker" in HotSpot.
>>>> (GCs may be able to expand the heap to fulfill allocation requests, if
>>>> the current capacity of the GC heap is smaller than the maximum capacity
>>>> configured. So disabling the GC isn't always as bad as it sounds.)
>>>>> I found an email on the archives that says that JNI critical sections do
>>>>> not effect operation of CMS and I’m interested in understanding the
>>>>> behavior for G1 as well.
>>>>> CMS is a mark-sweep collector, so it doesn't move objects. Thus, it is
>>>> possible to perform CMS old gen collections even when the GCLocker is
>>>> active (meaning there's at least one Java thread in a JNI critical section).
>>>> G1, on the other hand, is a moving collector (an incremental copying
>>>> collector with optional concurrent global marking; sometimes simply
>>>> referred to as a concurrent mark-compact collector, but it's not the usual
>>>> mark-compact notion). G1 GC cannot be performed when the GCLocker is active.
>>>>> This all boils down to the ability to use unsafe raw direct pointers in
>>>>> JNI
>>>>> without critical sections in HotSpot.
>>>>> Nope. Don't try that on HotSpot.
>>>> There are certain code patterns that might be able to access raw oops
>>>> safely without going into JNI critical sections. But that involves very
>>>> heavy VM internals knowledge, which is also subject to change without
>>>> notice, so practically don't try that.
>>>> Hope that helps,
>>>> Kris (OpenJDK username: kmo)
>>>>> Thank you,
>>>>> J

More information about the hotspot-dev mailing list