乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      JNI 對(duì)象在函數(shù)調(diào)用中的生命周期

       weicat 2010-01-27

      問題

      在 JNI 編程中常需要從一個(gè)普通的 C/C++ 函數(shù)中調(diào)用 JNI 方法,比如:

      long  ProcessKeyboardEventInJava(int keyboardEvent) {	     long    error = 0;     JNIEnv*    env = g_env;     jclass    that = g_class;     jmethodID    mid = g_mid;     …	…	     error  = env->CallStaticIntMethod(that, mid, keyboardEvent);      return error; } 

      ProcessKeyboardEventInJava 只是個(gè)普通的 C 函數(shù),目的是把參數(shù)中的鍵盤事件交給 Java 代碼處理。它并沒有 JNI 參數(shù),卻需要調(diào)用一個(gè) JNI 方法。那么調(diào)用所必需的參數(shù) JNIEnv,jclass 和 jmethodID,是如何獲得呢?從上面的代碼中可以看出,它們來自保存的全局變量 g_env,g_class 和 g_mid。這樣做對(duì)么?安全么?也許這段代碼在某種情況下,實(shí)現(xiàn)了軟件的需求,成功地執(zhí)行了 Java 的函數(shù),處理了這個(gè)鍵盤事件。在這種情況下,設(shè)計(jì)者很清楚,也深信 ProcessKeyboardEventInJava 只會(huì)在某個(gè) Native 函數(shù)返回前被調(diào)用。對(duì)應(yīng)的場(chǎng)景代碼應(yīng)該是這樣的:

      JNIEnv * g_env; jclass g_class; jmethodID g_mid;  JNIEXPORT jint JNICALL Java_SampleTest_init (JNIEnv *env, jclass cls) {	 	     g_class = cls;     g_env = env;	     g_mid = env->GetStaticMethodID(cls, "ProcessKeyboardEventInJava", "(III)I");     while(true)     {         ….         long error;         error = ProcessKeyboardEventInJava(theEvent)         ….     }  } 			

      但萬一 ProcessKeyboardEventInJava 在 Java_SampleTest_init(以下簡(jiǎn)稱 init)返回后的其他時(shí)機(jī)被調(diào)用了,會(huì)怎樣呢?那時(shí)可就沒有這么幸運(yùn)了,初衷是肯定達(dá)不到了,而發(fā)生 crash 或者 segmentation fault 這類錯(cuò)誤則幾乎是一定的。事實(shí)上,如上設(shè)計(jì),ProcessKeyboardEventInJava 也只允許在 init 函數(shù)中被調(diào)用。在其返回后被調(diào)用,就不合法了。所以,如果你是這個(gè)設(shè)計(jì)師,之前的設(shè)計(jì)中,是不是這個(gè)假設(shè)也有些太樂觀了呢?





      回頁首


      分析

      調(diào)用者本來以為這個(gè)函數(shù)能幫他的大忙,現(xiàn)在卻疑惑了,到底發(fā)生了什么?做錯(cuò)了什么呢?

      原因其實(shí)很簡(jiǎn)單,上面三個(gè)全局變量中的 g_class 已經(jīng)是非法的了,生命周期在退出 init 之后就結(jié)束了。

      這里要澄清的是 g_mid,由于它不是一個(gè) jobject,所以只要它對(duì)應(yīng)的 class 沒有被卸載,在退出 init 之后仍可以使用,沒問題;而 g_env 對(duì)于同一個(gè) thread 來說,它是唯一的,所以只要是 init 和 ProcessKeyboardEventInJava 處于一個(gè) thread,初始化后它的值在這個(gè) thread 沒有中止之前,都一直是合法的。

      那如何才能解決 g_class 的非法引用帶來的問題呢?

      這首先涉及到 Java 和 Native 代碼之間函數(shù)調(diào)用時(shí),參數(shù)如何傳遞的問題。簡(jiǎn)單類型,也就是內(nèi)置類型,比如 int, char 等是值傳遞(pass by value),而其它 Java 對(duì)象都是引用傳遞(pass by reference),這些對(duì)象引用由 JVM 傳給 Native 代碼,每個(gè)都有其生命周期。

      其次,Java 對(duì)象的生命周期是由它的引用類型決定的,這里的引用分兩種:local reference 和 global reference。Native 函數(shù)參數(shù)中 jobject 或者它的子類,其參數(shù)都是 local reference。Local reference 只在這個(gè) Native 函數(shù)中有效,Native 函數(shù)返回后,引用的對(duì)象就被釋放,它的生命周期就結(jié)束了。若要留著日后使用,則需根據(jù)這個(gè) local reference 創(chuàng)建 global reference。Global reference 不會(huì)被系統(tǒng)自動(dòng)釋放,它僅當(dāng)被程序明確調(diào)用 DeleteGlobalReference 時(shí)才被回收。





      回頁首


      解決

      于是解決的辦法就出來了:

      在 init 函數(shù)中,不是簡(jiǎn)單地把 jcalss 參數(shù)保存,而是:

      JNIEXPORT jint JNICALL Java_SampleTest_init (JNIEnv *env, jclass cls) {      ….     g_class= (jclass)(env->NewGlobalRef(cls));     …. } 			

      這樣,無論 ProcessKeyboardEventInJava 是在 init 返回前還是返回后,調(diào)用它都是安全的,可行的了。





      回頁首


      總結(jié)

      若要在某個(gè) Native 代碼返回后,還希望能繼續(xù)使用 JVM 提供的參數(shù)(比如 init 函數(shù)中的 jclass), 或者是過程中調(diào)用 JNI 函數(shù)的返回值(比如 g_mid),只要它是一個(gè) jobject, 則需要為它創(chuàng)建一個(gè) global reference,以后只能使用這個(gè) global reference;若不是一個(gè) jobject,則無需這么做。

      jclass 是由 jobject public 繼承而來的子類,所以它當(dāng)然是一個(gè) jobject,需要?jiǎng)?chuàng)建一個(gè) global reference 以便日后使用。而 jmethodID/jfieldID 與 jobject 沒有繼承關(guān)系,它不是一個(gè) jobject,只是個(gè)整數(shù),所以不存在被釋放與否的問題,可保存后直接使用。JNIEnv 對(duì)于每個(gè) thread 而言是唯一的,不能也不需要對(duì)它調(diào)用 NewGlobalReference。



      參考資料

      學(xué)習(xí)

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多