JNI使用内存相关问题记录


最近给服务器提供协议编解码库,出现较多内存相关的问题,做个记录,顺便给有相同需求的同学提供参考!


1、C/C++层创建对象,返回指针给Java层,Java层使用该指针作为后续操作的参数,在windows 64位系统中,出现地址无法访问的问题:


参考:https://www.jianshu.com/p/144136be6be9

在java与c构建多实例的案例中,java中对象保存一个long型成员变量,作为对应c实例的指针,jni层在新建c对象后,将对象指针(64位)转成长整型返回给java成员变量保存。然而在某些情况下,调用c实例的方法会出现ACCESS_VIOLATION,并且在windows上会报错,但在linux上就没问题。经过排查,问题最终定位如下:

在jni.h中,关于jlong(java long)的typedef并不是唯一的,在windows上,long总是32位(所以在linux上没问题),所以在jni层将地址转长整型的操作,必须要用__int64(long, long int, long long 都不行)保存变量,并返回给java。

 

JNIEXPORT jlong JNICALL Java_com_xdja_test_TestJNIUtil_getNativePointer(JNIEnv *env, jobject obj){

     

    char *key_list = (char *)malloc(200);

    if (key_list == NULL) {

        LOGD("key_list == null");

        return 0;

    }

    memset(key_list, 0, 200);


    printf("getNativePointer: obj:%08x, key_list:%08x,\r\n", obj, key_list);

    //return __int64(key_list); //windows需要返回的是这个地址

    //

    return jlong(key_list);

}



2、本地类对象方法和实例对象方法的声明不同:


//在创建支持的C/C++程序中添加两个方法,分别是非静态和静态,可以使用对应java类的类方法或者实例方法调用这些接口;

public native String stringFromJNI1();

public static native String stringFromJNI2();


extern "C"

JNIEXPORT jstring JNICALL

Java_com_xdja_test_TestJNIUtil_stringFromJNI1(JNIEnv *env, jobject instance) {


    // TODO

    return env->NewStringUTF(returnValue);

}


extern "C"

JNIEXPORT jstring JNICALL

Java_com_xdja_test_TestJNIUtil_stringFromJNI2(JNIEnv *env, jclass type) {


    // TODO

    return env->NewStringUTF(returnValue);

}



参考:https://blog.csdn.net/cloverjf/article/details/78654366?spm=1001.2014.3001.5501


3、Crash调试手段:

Android的NDK调试工具ndk-stack,ndk-stack是ndk开发工具包下提供的好用工具,能结合崩溃日志给出详细分析;

基础用法: ndk-stack -sym 带有符号表的so所在的目录 -dump 崩溃日志:

比如  ~/Library/Android/sdk/ndk/android-ndk-r16b/ndk-stack -sym app/build/intermediates/cmake/debug/obj/arm64-v8a -dump crash.log 


参考:https://blog.csdn.net/ReadyShowShow/article/details/109095211 


如果是给服务器或者Java应用程序使用的JNI库,调试Crash日志的方法,包括常规手段:日志法、return或者注释代码;

如果能从Core-dump中恢复出调用栈,那么调试效率就会高很多了!


补记:20210702

事出蹊跷必有因,在Linux平台运行正常的代码,在Windows平台就会出现异常,原来是Windows平台的calloc申请出来的内存并不会自动清0,导致结构体中指针对象为非法指针,内存释放就出现了野指针操作,崩溃也就不奇怪了!话说不能在同一个地方摔倒两次,但同时在这个地方卡了几天,真是惭愧!


visual studio 2017 中文注释影响代码逻辑,比方:

// 中文注释

if(xxx)  // 这一行被当作是注释了

{

    do_something...

}


switch(value){

    case 0:

    break;


    // 中文注释

    case 1: // 这一行被当作是注释了,导致case分支判断失败,走到了default分支

    break;


    default:

    break;

}


C代码最好是能做一次PC-lint检查内存相关问题,保证代码质量!


呱牛笔记

请先登录后发表评论
  • 最新评论
  • 总共0条评论