GetPrimitiveArrayCritical
将阻止所有现有的垃圾回收器。(实验性的谢南多厄收集器通常不会阻止。阻止垃圾回收器将阻止所有对象分配(一旦垃圾堆积起来)。
因此,使用规则如下:GetPrimitiveArrayCritical
-
不要调用任何 JNI 函数。各个部分的文档没有充分强调这一点,但这是您必须遵守的规则。原因是 JNI 函数可能会分配内存,尤其是本地引用。由于没有记录哪些 JNI 函数分配内存或分配内存多少,因此您无法调用其中任何一个。据推测,函数 EnsureLocalCapacity 可以预先分配本地引用来解决此问题,但没有人记录如何使用它。不要在关键区域内调用除 GetPrimitiveArrayCritical、GetStringCritical、ReleasePrimitiveArrayCritical 和 ReleaseStringCritical 以外的 JNI 函数,否则将陷入死锁。
-
不要以任何其他方式阻止可能需要从堆中分配内存的代码。这主要禁止阻止在同一 VM 中运行的 Java 代码。可以想象(但我不能肯定地说),你可以阻止不分配的Java代码。
-
您可以从其他线程调用 JNI 函数,只要您不阻塞等待这些线程即可。在其中调用 JNI 函数的线程可能会停止。请参阅下一点。
-
在关键区域中花费太多时间会使其他线程停止。根据您正在运行的线程数及其分配速率,您可以在关键区域中花费的时间可能会有所不同。在单线程应用程序中,或者在分配很少的多线程应用程序中,您可以安全地在关键区域中无限期地度过。但是,在其他情况下,您将使线程停止太多,以至于性能优势将被完全否定。然而,从正确性的角度来看,失速是安全的(而不是死锁)。
GetPrimitiveArrayCritical
- 您可以嵌套 和 方法,它们是线程安全的。
Get*Critical
Release*Critical
- 检查 的返回值并正确设置,因为允许方法失败和/或进行复制,就像 .
null
mode
Get*Critical
Get*ArrayElements
-
如果您正在编写一个库,并且正在考虑使用
GetPrimitiveArrayCritical
,请创建一个运行时选项来改用 Get*ArrayElements
。即使您没有遇到GetPrimitiveArrayCritical引起的停滞,您的用户也可能会遇到。
如果您在关键区域内调用 JNI 函数,Java 标志将向您发出警告。忽略那些说有时可以在关键区域内调用 JNI 函数的文档。事实并非如此。-Xcheck:jni
Java 8 标志将打印有关停滞的分配和集合的有用日志消息。要查找的消息可以从 src/share/vm/memory/gcLocker 中收集.cpp-XX:+PrintJNIGCStalls -XX:+PrintGCDetails
在 Java 9 中,日志记录已更改。打开 gc 和 jni 的日志记录。要查找的消息可以从 src/share/vm/gc/shared/gcLocker 中收集.cpp
更多信息: