我从书籍Android应用程序中为Absolute Beginners和Temperature Convertor app from here制作了hello world应用程序 两者在模拟器上运行正常,但当我尝试在三星Note 2上运行它后,LogCat上出现错误
02-08 07:22:18.665: E/dalvikvm(30944): JNI ERROR (app bug): accessed stale local reference 0xbc00021 (index 8 in a table of size 8)
02-08 07:22:18.665: E/dalvikvm(30944): VM aborting
02-08 07:22:18.665: A/libc(30944): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 30944 (oid.temperature)
两个应用程序都打开了带有标题的节目布局,但没有在布局中显示任何其他视图
样品运行良好
设备:注意2 Samsung-gt_n7100
IDE:Eclipse版本3.8
操作系统:64位Windows 7
答案 0 :(得分:60)
因为android 4.0垃圾收集器被更改了。现在它在垃圾收集过程中移动对象,这可能会导致很多问题。
想象一下,你有一个指向一个对象的静态变量,然后这个对象被gc移动。由于android使用java对象的直接指针,这意味着你的静态变量现在指向内存中的随机地址,没有被任何对象占用或被不同类型的对象占用。这几乎可以保证您下次使用此变量时将获得EXC_BAD_ACCESS。
因此,android会为您提供JNI ERROR(app bug)错误,以防止您获得可判断的EXC_BAD_ACCESS。现在有两种方法可以避免这种错误。
您可以将清单中的targetSdkVersion设置为版本11或更低版本。这将启用JNI错误兼容模式并完全防止任何问题。这就是您的旧示例正在运行的原因。
您可以通过调用env-> NewGlobalRef(ref)来避免使用指向java对象的静态变量或在存储它们之前使作业引用全局化。 也许最重要的例子是保持jclass对象。通常,您将在JNI_OnLoad期间初始化静态jclass变量,因为只要应用程序正在运行,类对象就会保留在内存中。
此代码将导致崩溃:
static jclass myClass;
JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * reserved) {
myClass = env->FindClass("com/example/company/MyClass");
return JNI_VERSION_1_6;
}
虽然这段代码运行良好:
static jclass myClass;
JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * reserved) {
jclass tmp = env->FindClass("com/example/company/MyClass");
myClass = (jclass)env->NewGlobalRef(tmp);
return JNI_VERSION_1_6;
}
有关更多示例,请参阅Marek Sebera提供的链接:http://android-developers.blogspot.cz/2011/11/jni-local-reference-changes-in-ics.html