为什么JNI活动实例会阻止GC?

sky*_*ree 2 java garbage-collection jvm jvm-hotspot

布尔PSScavenge :: invoke_no_policy()

  ...
  if (GCLocker::check_active_before_gc()) {
    return false;
  }
  ...
Run Code Online (Sandbox Code Playgroud)

如您所见,如果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();
}
Run Code Online (Sandbox Code Playgroud)

活跃()

  // Accessors
  static bool is_active() {
    assert(SafepointSynchronize::is_at_safepoint(), "only read at safepoint");
    return is_active_internal();
  }
Run Code Online (Sandbox Code Playgroud)

is_active_internal()

  static bool is_active_internal() {
    verify_critical_count();
    return _jni_lock_count > 0;
  }
Run Code Online (Sandbox Code Playgroud)

_jni_lock_count

static volatile jint _jni_lock_count;  // number of jni active instances.
Run Code Online (Sandbox Code Playgroud)

_jni_lock_count跟踪当前处于临界区域的线程数。

apa*_*gin 5

_jni_lock_count 跟踪当前在关键区域中的线程数。

正如JNI规范建议的那样,JNI关键函数会暂时禁用垃圾收集。

调用GetPrimitiveArrayCritical之后,本机代码在调用ReleasePrimitiveArrayCritical之前不应运行很长时间。我们必须将这对函数中的代码视为在“关键区域”中运行。在关键区域内,本机代码不得调用其他JNI函数或任何可能导致当前线程阻塞并等待另一个Java线程的系统调用。(例如,当前线程不得在另一个Java线程正在写入的流上调用read。)

这些限制使本地代码更有可能获得阵列的未复制版本,即使VM不支持固定也是如此。例如,当本机代码持有指向通过GetPrimitiveArrayCritical获得的数组的指针时,VM可以暂时禁用垃圾收集