I am doing some research on how HotSpot performs garbage collection and / or heap compression while running JNI code.
It is well known that objects can be moved at any time in Java. I am trying to figure out finally if the JNI is prone to garbage collection effects. There are a number of JNI features to explicitly prevent garbage collection; for example GetPrimitiveArrayCritical. It makes sense that such a function exists if the links are really unstable. However, this makes no sense if they are not.
It seems that there is a significant portion of conflicting information on this subject, and I'm trying to figure it out.
JNI code runs in a safe place and can continue to work, unless it calls back to Java or calls some specific JVM methods, after which it can be stopped to prevent exit from safepoint (thanks Nitzan for comments).
What mechanism does the JVM use to block threads during pause pause
The above makes me think that garbage collection will start at the same time as the JNI code. It can't be safe, right?
To implement local references, the Java virtual machine creates a registry for each control transition from Java to its own method. Registry maps are irreplaceable local references to Java objects and saves objects from garbage collection. All Java objects passed the method (including those returned as JNI function calls) are automatically added to the registry. The registry is deleted after the return of its own method, which allows entries to collect garbage.
https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html#wp16789
Ok, so the links localare immutable, but that says nothing about compaction.
JVM , Java ™ , . GC, JVM , "" ".
, :
JVM , J2N, :
J2N , set, " " PushLocalFrame JNI.
http://www.ibm.com/support/knowledgecenter/en/SSYKE2_5.0.0/com.ibm.java.doc.diagnostics.50/diag/understanding/jni_transitions_j2n.html
, IBM local reference root set, . , .
GC , . . JNI . , JNI . .
, . , , . . JNI , , JNI . . JNI .
- GetPrimitiveArrayCritical Java ™, ReleasePrimitiveArrayCritical.
- GetStringCritical java.lang.String, , ReleaseStringCritical.
http://www.ibm.com/support/knowledgecenter/SSYKE2_6.0.0/com.ibm.java.doc.diagnostics.60/diag/understanding/jni_copypin.html
, IBM , JNI , ! HotSpot?
GetArrayElements , (, , ). , GetPrimitiveArrayCritical. , / ( ) , .
GC JNI?
, - Get<PrimitiveType>ArrayElements GetPrimitiveArrayCritical
.
, JVM ( , ), CMS GC, JNI ( , , - , - , , , , ). , ( ), , , (- ), - , ( ).
http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2007-December/000074.html
OpenJDK, , , GC ConcurrentMarkAndSweep .
https://www.infoq.com/articles/G1-One-Garbage-Collector-To-Rule-Them-All
G1 , , .
IBM , ; , JNI HotSpot . , , , , JNI.
HotSpot, . GetByteArrayElements. , . , .
GetByteArrayElements
#ifndef USDT2
#define DEFINE_GETSCALARARRAYELEMENTS(ElementTag,ElementType,Result, Tag)
JNI_QUICK_ENTRY(ElementType*,
jni_Get##Result##ArrayElements(JNIEnv *env, ElementType##Array array, jboolean *isCopy))
JNIWrapper("Get" XSTR(Result) "ArrayElements");
DTRACE_PROBE3(hotspot_jni, Get##Result##ArrayElements__entry, env, array, isCopy);
typeArrayOop a = typeArrayOop(JNIHandles::resolve_non_null(array));
ElementType* result;
int len = a->length();
if (len == 0) {
result = (ElementType*)get_bad_address();
} else {
result = NEW_C_HEAP_ARRAY_RETURN_NULL(ElementType, len, mtInternal);
if (result != NULL) {
memcpy(result, a->Tag##_at_addr(0), sizeof(ElementType)*len);
if (isCopy) {
*isCopy = JNI_TRUE;
}
}
}
DTRACE_PROBE1(hotspot_jni, Get##Result##ArrayElements__return, result);
return result;
JNI_END
JNI_QUICK_ENTRY
extern "C" { \
result_type JNICALL header { \
JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
assert( !VerifyJNIEnvThread || (thread == Thread::current()), "JNIEnv is only valid in same thread"); \
ThreadInVMfromNative __tiv(thread); \
debug_only(VMNativeEntryWrapper __vew;) \
VM_QUICK_ENTRY_BASE(result_type, header, thread)
- . , , __tiv, , , .
- - , JNI,
GetByteArrayElements, ? - , - , JNI VM Native,
JNI_QUICK_ENTRY ?