JNI transitions
To understand JNI local reference management and the GC, you must understand the context of a running thread attached to the JVM. Every thread has a runtime stack that includes a frame for each method call. From a GC perspective, every stack establishes a thread-specific "root set" including the union of all JNI local references in the stack.

Each method call in a running VM adds (pushes) a frame onto the stack, just as every return removes (pops) a frame. Each call point in a running stack can be characterized as one of the following types:
- Java™ to Java (J2J)
- Native to Native (N2N)
- Java to Native (J2N)
- Native to Java (N2J)
You can only perform an N2J transition in a thread that meets the following conditions:
- The process containing the thread must contain a JVM started using the JNI Invocation API.
- The thread must be "attached" to the JVM.
- The thread must pass at least one valid local or global object reference to JNI.
J2J and N2N transitions
Because object references do not change form as part of J2J or N2N transitions, J2J and N2N transitions do not affect JNI local reference management.
Any section of N2N code that obtains many local references without promptly returning to Java can needlessly stress the local reference capacity of a thread. This problem can be avoided if local references are managed explicitly by the native method programmer.
N2J transitions
For native code to call Java code (N2J) in the current thread, the thread must first be attached to the JVM in the current process.
Every N2J call that passes object references must have obtained them using JNI, therefore they are either valid local or global JNI refs. Any object references returned from the call are JNI local references.
J2N calls
The JVM must ensure that objects passed as parameters from Java to the native method and any new objects created by the native code remain reachable by the GC. To handle the GC requirements, the JVM allocates a small region of specialized storage called a local reference root set.
A local reference root set is created when:
- A thread is first attached to the JVM (the outermost root set of the thread).
- Each J2N transition occurs.
- A local reference to the caller's object or class.
- A local reference to each object passed as a parameter to the native method.
- NewLocalRef
- DeleteLocalRef
- PushLocalFrame
- PopLocalFrame
- EnsureLocalCapacity
J2N returns
When native code returns to Java, the associated JNI local reference "root set", created by the J2N call, is released.
If the JNI local reference was the only reference to an object, the object is no longer reachable and can be considered for garbage collection. Garbage collection is triggered automatically by this condition, which simplifies memory management for the JNI programmer.