• JNI错误总结(转)


    源:JNI错误总结

      最近公司里要用JNI技术,用java去调用已经写好的本地DLL库。之前自己也没接触过相关技术,其中花了大部分时间在调试改错上面,网上对于错误的解决方案也不多,现在项目接近完工,自己也该把其中碰到的一些问题进行一下汇总。

      1.相关命令:

       将包含native函数的java源代码生成JNI的.h头文件:  javah  -jni com.xxx.test  

       注意:test是编译后的.class文件,要写完整路径,该命令在com的上层目录下进行。更完整的命令为: javah -classpath . -jni com.xxx.test  注意中间的点号

       编写实现上面.h文件的.cpp代码后,生成dll目标文件:g++ -Wl,--kill-at -shared -o test1.dll test2.cpp 

       注意:test1.dll为生成的目标DLL,test2为cpp源文件。红色部分不可少,表示生成不带@的函数.

      

      2.如何将java里的string类型转换为C里的char*类型:

    char* jstringTostring(JNIEnv* env, jstring jstr) //change type string into char*
    {
        char* rtn = NULL;
        jclass clsstring = env->FindClass("java/lang/String");
        jstring strencode = env->NewStringUTF("utf-8");
        jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
        jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
        jsize alen = env->GetArrayLength(barr);
        jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
        if (alen > 0)
        {
            rtn = (char*)malloc(alen + 1);
            memcpy(rtn, ba, alen);
            rtn[alen] = 0;
        }
        env->ReleaseByteArrayElements(barr, ba, 0);
        return rtn;
    }

    3.如何将C里的char*类型转换为java里的string类型:

    jstring stoJstring(JNIEnv* env, const char* pat)//change type char* into string
    {
        jclass strClass = env->FindClass("Ljava/lang/String;");
        jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
        jbyteArray bytes = env->NewByteArray(strlen(pat));
        env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
        jstring encoding = env->NewStringUTF("utf-8");
        return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
    }

    4.JNI里如何返回arraylist类型:

    jclass cls_ArrayList = env->FindClass("java/util/ArrayList");  
            jmethodID construct = env->GetMethodID(cls_ArrayList,"<init>","()V");//注意第二个参数为<init>,网上有些资料写着为空或者<init></init>是错的。  
            jobject obj_ArrayList = env->NewObject(cls_ArrayList,construct,"");  
            jmethodID arrayList_add = env->GetMethodID(cls_ArrayList,"add","(Ljava/lang/Object;)Z"); //获得arraylist的add()方法 
            //User Object  
            jclass cls_user = env->FindClass("User"); //注意User所在路径要写完整,该加包名的地方要加上 
            //none argument construct function  
            jmethodID construct_user = env->GetMethodID(cls_user,"<init>","()V");  
            //new a object  
            jobject obj_user = env->NewObject(cls_user,construct_user,"");  
            //get method id  
            /* 
            jmethodID user_setId = env->GetMethodID(cls_user,"setId","(J)V"); 
            jmethodID user_setUserName = env->GetMethodID(cls_user,"setUserName","(Ljava/lang/String;)V"); 
            jmethodID user_setMan = env->GetMethodID(cls_user,"setMan","(Z)V"); 
            jmethodID user_setAge = env->GetMethodID(cls_user,"setAge","(I)V"); 
            */  
            int i;  
            for(i=0;i<10;i++){  
            //new a object  
            jobject obj_user = env->NewObject(cls_user,construct_user,"");  
            //get field id  
            jfieldID user_id = env->GetFieldID(cls_user,"id","J");  
            jfieldID user_name = env->GetFieldID(cls_user,"userName","Ljava/lang/String;");  
            jfieldID user_isMan = env->GetFieldID(cls_user,"isMan","Z");  
            jfieldID user_age = env->GetFieldID(cls_user,"age","I");  
            env->SetLongField(obj_user,user_id,i);  
            env->SetObjectField(obj_user,user_name,env->NewStringUTF("CC"));  
            env->SetBooleanField(obj_user,user_isMan,1);  
            env->SetIntField(obj_user,user_age,21);  
            env->CallObjectMethod(obj_ArrayList,arrayList_add,obj_user);  
            }  
            return obj_ArrayList;
    }


    5.对于碰到以下错误:

    # A fatal error has been detected by the Java Runtime Environment:
    #
    # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x7c92100b, pid=596, tid=2080
    #
    # JRE version: 6.0_21-b07
    # Java VM: Java HotSpot(TM) Client VM (17.0-b17 mixed mode, sharing windows-x86 )
    # Problematic frame:
    # C [ntdll.dll+0x100b]
    #
    # If you would like to submit a bug report, please visit:
    # http://java.sun.com/webapps/bugreport/crash.jsp
    # The crash happened outside the Java Virtual Machine in native code.
    # See problematic frame for where to report the bug.

      一般都是由于你所写的JNI转换后的CPP实现代码有问题。可以关注下红色部分,若pc=0x00000000,则表示你要实现的native函数里传入了空指针void*或null。

      而如果你传入的参数还有结构体变量,那么这里的空值还要考虑结构体里的部分成员是否也为空,JNI里的函数是不允许传入空值的,这点网上的资料里都没有提,我也在这里卡了很久。但是你必须要传入空值,而且还要调用更下一层的DLL里的函数时,那就会报错,这时该怎么办呢?此时你可以在它们中间再加一过渡层(CPP文件)实现间接调用。  

      6.最后注意下JNI里的资源释放问题,若使用资源过多没有及时释放,也会有可能会报上面的错误。

      如:env->ReleaseStringUTFChars(xxx, xxx);

      至于其他问题网上都有就不写了。

  • 相关阅读:
    JavaScript知识回顾
    HTML和CSS相关知识回顾
    springmvc文件上传和下载
    jsp页面调试中的问题记录
    mybatis传参的几种方式
    ssm中调试遇到的坑
    idea新手日记
    Oracle安装
    mysql5安装
    Servlet 的原理----无脑笔记
  • 原文地址:https://www.cnblogs.com/LittleTiger/p/4660730.html
Copyright © 2020-2023  润新知