调试 JNI

如果您认为 JNI 存在问题,那么可以运行检查来帮助您诊断 JNI 转换。

JNI 代码中的错误可能以多种方式发生:
  • 在执行本机方法的过程中程序发生崩溃(最为常见)。
  • 在从本机方法返回后(通常在 GC 期间),程序有时会发生崩溃(并不常见)。
  • 在从本机方法返回后不久,错误的 JNI 代码导致死锁(偶尔发生)。

如果您认为用户编写的本机代码与 JVM 之间的交互存在问题(即,JNI 问题),那么可以运行检查来帮助您诊断 JNI 转换。 要运行这些检查,请在启动 JVM 时指定 -Xcheck:jni 选项。

-Xcheck:jni 选项会激活一组围绕 JNI 函数的包装器函数。 包装函数会对入局参数执行检查。 这些检查包括:
  • 调用和初始化 JNI 的调用是否位于同一线程上。
  • 对象参数是否是有效的对象。
  • 局部或全局引用是否引用了有效的对象。
  • 字段类型是否与 Get<Type>FieldSet<Type>Field 调用相匹配。
  • 静态和非静态字段标识是否有效。
  • 字符串是否有效且不为空。
  • 数组元素是否不为空。
  • 数组元素的类型。

来自 -Xcheck:jni 的输出显示在标准错误流上,如下所示:

JVMJNCK059W: JNI warning in FindClass: argument #2 is a malformed identifier ("invalid.name")
JVMJNCK090W: Warning detected in com/ibm/examples/JNIExample.nativeMethod() [Ljava/lang/String];
第一行表示:
  • 错误级别(错误、警告或建议)。
  • 在其中检测到错误的 JNI API。
  • 问题解释。
最后一行表示检测到错误时执行的本机方法。

您可以使用 -Xcheck:jni:<suboption>[,<...>] 来指定其他子选项。 可用的子选项包括:

all
检查应用程序和系统类。
verbose
跟踪某些 JNI 函数和活动。
trace
跟踪所有 JNI 函数。
nobounds
不对字符串和数组执行边界检查。
nonfatal
检测到错误时不退出。
nowarn
不显示警告。
noadvice
不显示建议。
novalist
不检查 va_list 的复用情况(请参阅本节结尾部分的“注释”)。
pedantic
执行更为全面的检查,但速度较慢。
valist
检查 va_list 的复用情况(请参阅本节结尾部分的“注释”)。
help
打印帮助信息。

-Xcheck:jni 选项可能会降低性能,因为它会彻底验证提供的参数。

注:

在某些平台上,在第二次 JNI 调用中复用 va_list(例如,使用相同的自变量对 CallStaticVoidMethod() 调用两次)将导致 va_list 被损坏以及第二次调用失败。 要确保不损坏 va_list,请在第一次调用中使用标准 C 宏 va_copy()。 缺省情况下,-Xcheck:jni 可确保不复用 va_list。 仅当您的平台允许在不使用 va_copy的情况下复用 va_list 时,才使用 novalist 子选项来禁用此检查。 z/OS® 平台允许 va_list 复用,缺省情况下使用 -Xcheck:jni:novalist 。 要启用 va_list 复用检查,请使用 -Xcheck:jni:valist 选项。