zoukankan      html  css  js  c++  java
  • android 内存泄露之jni local reference table overflow (max=512)

    在android项目中要实现一个需求

    为了性能的要求只能用c代码来实现功能。

    这样就牺牲了java跨平台性。

    通过加载.so的方式,把用c实现的模块集成到app中。

    android提供jni层,作为一个适配器。

    可以在java层调用c接口,在jni层可以通过java提供的反射机制调用java接口和创建java对象。

    最后需求完成了,自测也没问题,嘻嘻,自己也开心了一下,但是提交测试后,测试人员马上报了一个bug。

    出现local reference table overflow (max=512)这样的一个错误。我去,尽然出现了崩溃。

    google和百度了半天,才发现原来发生了jni层的内存泄露,导致了崩溃。

    jni层到底出现了啥内存泄露????

    从java代码进入jni层本地代码调用时,Dalvik就创建了一张local reference表来存储local reference,这张表

    的表项数有最大值限制,一般最大为都是512个,local reference表只有当退出jni层代码的调用是才会清除掉。

    当表项数超过最大值限制时,Dalvik就会抛出异常,导致了崩溃。

    何为local reference????

    他是在native代码层他是一个本地变量和java对象的引用。

    JNIEXPORT jint JNICALL Java_com_print(JNIEnv *env, jobject obj){

      char data[] = "daffdasf";

        jstring content = (*env)->NewStringUTF(env, data);

    }

    变量content在 函数Java_com_print中是一个本地变量并且是String对象一个引用。所以会在local reference table

    中追加一个表项来指向java对象。

    其实每次进入native代码都会存在一个全局指向local reference table起始位置的ptr变量。

    而上面函数中的content只是代表一个在local reference table中的偏移,通过ptr + content偏移

    从local reference table获取java对象的值。

    什么原因会发生local reference table overflow?????

    那就是在一个循环中不断的创建local reference,而没有调用DeleteLocalRef去销毁这个local reference,

    从而导致local reference table中表项不断增加,最后超过最大值,抱出了异常,导致了崩溃。

    举两个例子哈:

    例子1.

    JNIEXPORT jint JNICALL Java_com_example(JNIEnv *env, jobject obj){

      char data[] = "daffdasf";

      int i = 0;

      for(i = 0;i < 1000;i++){

        jstring content = (*env)->NewStringUTF(env, data);

      }

    }

    例子1代码会导致local reference table overflow

    例子2.

    int Java_com_example(char * data){

       JNIEnv *env = NULL;
       JavaVM * vm = NULL;

      vm = getVm();

      (*vm)->AttachCurrentThread(vm, &env, NULL);

         jstring content = (*env)->NewStringUTF(env, data);

    }

    void callExample(){

      int i = 0;

      char data [] = "dafdfdasfds";

      for(i = 0;i < 1000;i++){

        Java_com_example(data);

      }

    }

    例子2代码会导致local reference table overflow

    大家写jni的代码时要防止jni层的内存泄露,要注意用本地语言的方式清除本地语言获得的内存,

    也要注意local reference和global reference的使用。

    当然jni官文文档中没有告诉我们jni层实现的细节,只告诉我们如何规范的编写jni代码,这当然是正确的做法。

    对于使用者来说只需要关注的他的使用不需要关注实现细节,这样就保证了可扩展性。

    所以对于不同的对local reference的实现可能结果不一样,就有可能不出现上面local reference table overflow的错误了。

  • 相关阅读:
    rest framework 认证 权限 频率
    rest framework 视图,路由
    rest framework 序列化
    10.3 Vue 路由系统
    10.4 Vue 父子传值
    10.2 Vue 环境安装
    10.1 ES6 的新增特性以及简单语法
    Django 跨域请求处理
    20190827 On Java8 第十四章 流式编程
    20190825 On Java8 第十三章 函数式编程
  • 原文地址:https://www.cnblogs.com/lzl-sml/p/3520052.html
Copyright © 2011-2022 走看看