JNI检测到应用错误:jarray为NULL,是否由我的代码导致?
让我帮你拆解这个Logcat片段,一步步判断是不是你的代码导致了这个JNI错误:
1. 先看错误核心提示
最顶部的两行已经点明了错误类型和触发点:
05-14 19:27:27.869 4565-4571/com.example.jni A/zygote: java_vm_ext.cc:534] JNI DETECTED ERROR IN APPLICATION: jarray was NULL
05-14 19:27:27.869 4565-4571/com.example.jni A/zygote: java_vm_ext.cc:534] in call to GetIntArrayElements
这说明调用GetIntArrayElements时传入了NULL数组,但关键是要搞清楚是谁在调用这个函数。
2. Native栈追踪是判断归属的核心
接下来看Logcat里的native: #xx pc xxxxxxxx /system/lib/xxx.so这些栈帧条目:
- 如果错误是你的JNI代码导致的,栈里一定会有一行指向你自己的原生库(比如
/data/app/com.example.jni-xxxx/lib/arm/libyour-jni-lib.so),后面会跟着你代码里的函数名或者内存偏移地址。 - 但在你提供的Logcat里,所有native栈帧都是系统库:
libart.so(ART运行时)、libopenjdkjvmti.so(JVM TI工具库)、libart-compiler.so(ART编译组件),完全没有出现你的应用的原生库条目。
3. 线程上下文帮你定位触发场景
再看线程信息:
05-14 19:27:27.869 4565-4571/com.example.jni A/zygote: java_vm_ext.cc:534] "Jit thread pool worker thread 0" daemon prio=5 tid=2 Runnable
这个线程是Android Runtime的JIT编译后台线程,不是你应用的业务线程(比如Main线程、你自己创建的Native线程)。这说明错误不是在你主动调用JNI方法时触发的,而是系统JIT编译器在后台工作时出的问题。
4. 调用链上下文还原错误场景
从栈帧的逆序(从#15往#11看)可以看到:
错误是在openjdkjvmti::JvmtiAllocationListener::ObjectAllocated这个VM TI内存分配监听函数里触发的,随后进入了JIT编译流程。这大概率是系统层面的问题,或者是你启用了某些JVM TI相关的调试/监控工具(比如性能分析、内存检测工具)导致的,和你的JNI代码本身无关。
给你的后续建议
- 先检查是否启用了第三方调试、监控或性能分析工具,暂时关闭它们再测试;
- 如果没有启用这类工具,可能是ART runtime的版本bug,可以尝试更换不同Android版本的设备/模拟器测试;
- 作为防御性编程,你可以在自己的JNI代码里添加NULL检查:调用
GetIntArrayElements前先判断传入的jintArray是否为NULL,比如:
这能避免未来你的代码出现类似问题,但从当前Logcat看,这次错误不是你的代码直接导致的。if (array == NULL) { // 处理NULL情况,比如返回错误码或直接返回 return; } jint* elements = env->GetIntArrayElements(array, NULL);
内容的提问来源于stack exchange,提问作者NoonanRosenblum

