Android中JNI调用时出现accessed stale local reference的问题

之前在做一个native的模块时遇到这样一个问题:

代码运行在android2.3上没有任何问题,可是在4.2上运行时报出了:JNI ERROR (app bug): accessed stale local reference 的错误。

后来在StackOverflow上找到了问题的答案。简单来说就是  4.0以上的android系统GC在垃圾回收时为了减少内存碎片,会对内存进行整理,整理时必然会移动对象的内存地址,这时C代码的指针还指向原来对象的地址,这时该对象已经被移动到了其他位置,因此会出现问题。

解决办法见原文:

Since android 4.0 garbage collector was changed. Now it moves object around during garbage collection, which can cause a lot of problems.

Imagine that you have a static variable pointing to an object, and then this object gets moved by gc. Since android uses direct pointers for java objects, this would mean that your static variable is now pointing to a random address in the memory, unoccupied by any object or occupied by an object of different sort. This will almost guarantee that you‘ll get EXC_BAD_ACCESS next time you use this variable.

So android gives you JNI ERROR (app bug) error to prevent you from getting undebugable EXC_BAD_ACCESS. Now there are two ways to avoid this error.

  1. You can set targetSdkVersion in your manifest to version 11 or less. This will enable JNI bug compatibility mode and prevent any problems altogether. This is the reason why your old examples are working.
  2. You can avoid using static variables pointing to java objects or make jobject references global before storing them by calling env->NewGlobalRef(ref).
    Perhaps on of the biggest examples here is keeping jclass objects. Normally, you‘ll initialize static jclass variable during JNI_OnLoad, since class objects remain in the memory as long as the application is running.

This code will lead to a crash:

static jclass myClass;

JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * reserved) {
    myClass = env->FindClass("com/example/company/MyClass");
    return JNI_VERSION_1_6;
}

While this code will run fine:

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;
}

For more examples see link provided by Marek Sebera: http://android-developers.blogspot.cz/2011/11/jni-local-reference-changes-in-ics.html

时间: 2024-12-28 23:55:23

Android中JNI调用时出现accessed stale local reference的问题的相关文章

Jni Error(app bug): accessed stale local reference 的另类出现方式

Jni Error(app bug): accessed stale local reference 这个错误平常是 弱全局变量引起的时候 出现的一个错误,但是今天我却在另外一种情况下遇到了 下面是错误截图 出现错误的原因其他很简单 是因为自己的粗心引起的 java层函数声明是这么写的 public native String screenshot(int x,int y,int x1,int y1,byte[] path); jni是这么写的 void Java_java_api_JniUti

JNI ERROR (app bug): accessed stale local reference 0xbc00021

在android ndk编程时,要使用到.so文件,so文件使用c语言编写的.当我在c文件中调用java类时,第一次调用时没问题的,但第二次调用的时候就失败了.上网搜了很多资料,大概原因是在jni中,使用指针指向某一个java对象的时候,由于android的垃圾回收机制(Garbage Collector),如果java对象被回收的话,那么指针指向的对象就会为空或者不存在,从而提示JNI ERROR:accessed stale(陈旧的,落后的) local reference 大概的意思就是变

cordova调用Notification插件部分手机报错JNI ERROR (app bug): accessed stale local reference

写了一个Android notification本地通知插件,在4.0版本的小米出现了问题. 使用了Notification.Builder的方法.但是小米这个会报标题上的错误. 于是改为旧的方法做兼容. Notification notify = new Notification(R.drawable.icon,args.getString(0),System.currentTimeMillis()); notify.setLatestEventInfo(cx, args.getString(

Android中JNI调用过程简述

1.安装和下载cygwin,下载Android NDK: 2.在ndk项目中JNI接口的设计: 3.使用C/C++实现本地方法: 4.JNI生成动态链接库.so文件: 5.将动态链接库复制到java工程,在Java工程中调用,运行Java工程即可.

Android中JNI的使用

Android中JNI编程的那些事儿 首先说明,Android系统不允许一个纯粹使用C/C++的程序出现,它要求必须是通过Java代码嵌入Native C/C++——即通过JNI的方式来使用本地(Native)代码.因此JNI对Android底层开发人员非常重要. 如何将.so文件打包到.APK 让我们 先 从最简单的情况开始,假如已有一个JNI实现——libxxx.so文件,那么如何在APK中使用它呢? 在我最初写类似程序的时候,我会将libxxx.so文件push到/system/lib/目

Android中Activity切换时共享视图元素的切换动画(4.x兼容方案)

同时发布在我的博客 点此进入 开始 上一篇讲了使用 Google 的 AppCompat-v7 来实现 Activity 切换时实现共享视图元素的切换动画.这一篇介绍两个可以兼容 4.x 的两个第三方方案. 上一篇:Android中Activity切换时共享视图元素的切换动画(5.0以上) 方案一:PreLollipopTransition 首先在 build.gradle 配置文件添加这个库依赖 dependencies { compile 'com.kogitune:pre-lollipop

Android中如何调用拨打电话?

Android系统原本就为手机设计,所以,在android系统中的任何App中,只要愿意,拨打指定电话非常方便. 核心就是使用Intent跳转,指定请求Action为Intent.ACTION_CALL 即可. [源码下载] http://www.code4apk.com/android-code/178 核心代码如下: 1 Intent intent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:13888888888"); 下面一起来

Android中ListView选中时的黄色底色

Android的ListView中默认选中时底色为黄色,如何去掉呢 其中会用到一个属性: android:listSelector="#00000000" 这样就行了 Android中ListView选中时的黄色底色

Android中连接蓝牙设备时遇到createRfcommSocketToServiceRecord的UUID问题和BluetoothSocket的connect失败

[问题] 折腾: [记录]编写Android中的蓝牙模块驱动和底层HART设备 期间,参考: Bluetooth | Android Developers – ManagingAConnection 参考“Connecting as a client”中的: tmp = device.createRfcommSocketToServiceRecord(MY_UUID); 遇到UUID不懂的问题. 然后随便去 http://www.guidgenerator.com/online-guid-gen