为什么SetByteArrayRegion不会损坏内存?

时间:2019-05-31 13:29:27

标签: java garbage-collection jvm java-native-interface jvm-hotspot

SetByteArrayRegion函数的实现方式为

JNI_ENTRY(void, \
jni_Set##Result##ArrayRegion(JNIEnv *env, ElementType##Array array, jsize start, \
             jsize len, const ElementType *buf)) \
  JNIWrapper("Set" XSTR(Result) "ArrayRegion"); \
  DTRACE_PROBE5(hotspot_jni, Set##Result##ArrayRegion__entry, env, array, start, len, buf);\
  DT_VOID_RETURN_MARK(Set##Result##ArrayRegion); \
  typeArrayOop dst = typeArrayOop(JNIHandles::resolve_non_null(array)); \
  if (start < 0 || len < 0 || ((unsigned int)start + (unsigned int)len > (unsigned int)dst->length())) { \
    THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); \
  } else { \
    if (len > 0) { \
      int sc = TypeArrayKlass::cast(dst->klass())->log2_element_size(); \
      memcpy((u_char*) dst->Tag##_at_addr(start), \
             (u_char*) buf, \
             len << sc);    \
    } \
  } \
JNI_END

可以看出,它在指向Java堆数组的本地指针memcpy上调用dst->Tag##_at_addr(start)memcpy本身不是原子的,因此我得出结论,没有什么可以阻止GC在memcpy调用的中间移动数组。

此外,数组可以在dst->Tag##_at_addr(start)之后再次移动到某个位置,从而再次导致内存损坏。

根据合同,“关键”方法使用GC_locker::lock_critical(thread);

那么SetArrayRegion方法为什么安全?我想念什么?

1 个答案:

答案 0 :(得分:4)

如您所见,该函数包装在JNI_ENTRY宏中,该宏又执行ThreadInVMfromNative状态转换。这意味着,保证执行SetByteArrayRegion的Java线程处于_thread_in_vm状态。

非并行压缩收集器只能在全局安全点移动对象。一个安全点意味着所有Java线程都被阻止或正在运行本机代码(_thread_in_native状态)。

因此,如果在SetByteArrayRegion运行时请求安全点,则JVM将等待所有线程完成当前VM操作。反之,如果SetByteArrayRegion在GC运行时执行,则线程将在状态转换时阻塞,直到GC完成。

相关问题