为什么 JNI 活动实例会阻止 GC?
Why do JNI active instances prevent GC?
bool PSScavenge::invoke_no_policy()
...
if (GCLocker::check_active_before_gc()) {
return false;
}
...
如您所见,如果 GCLocker::check_active_before_gc()
是 true
,它不会调用次要 GC,即 PSScavenge::invoke_no_policy()
。为什么会这样?
check_active_before_gc()
bool GCLocker::check_active_before_gc() {
assert(SafepointSynchronize::is_at_safepoint(), "only read at safepoint");
if (is_active() && !_needs_gc) {
verify_critical_count();
_needs_gc = true;
log_debug_jni("Setting _needs_gc.");
}
return is_active();
}
is_active()
// Accessors
static bool is_active() {
assert(SafepointSynchronize::is_at_safepoint(), "only read at safepoint");
return is_active_internal();
}
is_active_internal()
static bool is_active_internal() {
verify_critical_count();
return _jni_lock_count > 0;
}
_jni_lock_count
static volatile jint _jni_lock_count; // number of jni active instances.
_jni_lock_count
跟踪正在运行的线程数
目前处于临界区。
_jni_lock_count
跟踪当前处于临界区的线程数。
作为 suggested by JNI specification,JNI 关键函数暂时禁用垃圾收集。
After calling GetPrimitiveArrayCritical, the native code should not
run for an extended period of time before it calls
ReleasePrimitiveArrayCritical. 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, or any system
call that may cause the current thread to block and wait for another
Java thread. (For example, the current thread must not call read on a
stream being written by another Java thread.)
These restrictions make it more likely that the native code will
obtain an uncopied version of the array, even if the VM does not
support pinning. For example, a VM may temporarily disable garbage
collection when the native code is holding a pointer to an array
obtained via GetPrimitiveArrayCritical.
bool PSScavenge::invoke_no_policy()
...
if (GCLocker::check_active_before_gc()) {
return false;
}
...
如您所见,如果 GCLocker::check_active_before_gc()
是 true
,它不会调用次要 GC,即 PSScavenge::invoke_no_policy()
。为什么会这样?
check_active_before_gc()
bool GCLocker::check_active_before_gc() {
assert(SafepointSynchronize::is_at_safepoint(), "only read at safepoint");
if (is_active() && !_needs_gc) {
verify_critical_count();
_needs_gc = true;
log_debug_jni("Setting _needs_gc.");
}
return is_active();
}
is_active()
// Accessors
static bool is_active() {
assert(SafepointSynchronize::is_at_safepoint(), "only read at safepoint");
return is_active_internal();
}
is_active_internal()
static bool is_active_internal() {
verify_critical_count();
return _jni_lock_count > 0;
}
_jni_lock_count
static volatile jint _jni_lock_count; // number of jni active instances.
_jni_lock_count
跟踪正在运行的线程数
目前处于临界区。
_jni_lock_count
跟踪当前处于临界区的线程数。
作为 suggested by JNI specification,JNI 关键函数暂时禁用垃圾收集。
After calling GetPrimitiveArrayCritical, the native code should not run for an extended period of time before it calls ReleasePrimitiveArrayCritical. 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, or any system call that may cause the current thread to block and wait for another Java thread. (For example, the current thread must not call read on a stream being written by another Java thread.)
These restrictions make it more likely that the native code will obtain an uncopied version of the array, even if the VM does not support pinning. For example, a VM may temporarily disable garbage collection when the native code is holding a pointer to an array obtained via GetPrimitiveArrayCritical.