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

 

  至於其他問題網上都有就不寫了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM