调试 JNI
如果您认为 JNI 存在问题,那么可以运行检查来帮助您诊断 JNI 转换。
JNI 代码中的错误可能以多种方式发生:
- 在执行本机方法的过程中程序发生崩溃(最为常见)。
- 在从本机方法返回后(通常在 GC 期间),程序有时会发生崩溃(并不常见)。
- 在从本机方法返回后不久,错误的 JNI 代码导致死锁(偶尔发生)。
如果您认为用户编写的本机代码与 JVM 之间的交互存在问题(即,JNI 问题),那么可以运行检查来帮助您诊断 JNI 转换。 要运行这些检查,请在启动 JVM 时指定 -Xcheck:jni 选项。
-Xcheck:jni 选项会激活一组围绕 JNI 函数的包装器函数。 包装函数会对入局参数执行检查。 这些检查包括:
- 调用和初始化 JNI 的调用是否位于同一线程上。
- 对象参数是否是有效的对象。
- 局部或全局引用是否引用了有效的对象。
- 字段类型是否与
Get<Type>Field
或Set<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 选项。