国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
JNI 對(duì)象在函數(shù)調(diào)用中的生命周期

問(wèn)題

在 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ù)中的鍵盤(pán)事件交給 Java 代碼處理。它并沒(méi)有 JNI 參數(shù),卻需要調(diào)用一個(gè) JNI 方法。那么調(diào)用所必需的參數(shù) JNIEnv,jclass 和 jmethodID,是如何獲得呢?從上面的代碼中可以看出,它們來(lái)自保存的全局變量 g_env,g_class 和 g_mid。這樣做對(duì)么?安全么?也許這段代碼在某種情況下,實(shí)現(xiàn)了軟件的需求,成功地執(zhí)行了 Java 的函數(shù),處理了這個(gè)鍵盤(pán)事件。在這種情況下,設(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)         ….     }  } 			

但萬(wàn)一 ProcessKeyboardEventInJava 在 Java_SampleTest_init(以下簡(jiǎn)稱 init)返回后的其他時(shí)機(jī)被調(diào)用了,會(huì)怎樣呢?那時(shí)可就沒(méi)有這么幸運(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è)也有些太樂(lè)觀了呢?





回頁(yè)首


分析

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

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

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

那如何才能解決 g_class 的非法引用帶來(lái)的問(wèn)題呢?

這首先涉及到 Java 和 Native 代碼之間函數(shù)調(diào)用時(shí),參數(shù)如何傳遞的問(wèn)題。簡(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í)才被回收。





回頁(yè)首


解決

于是解決的辦法就出來(lái)了:

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

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

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





回頁(yè)首


總結(jié)

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

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



參考資料

學(xué)習(xí)
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android JNI開(kāi)發(fā)高級(jí)篇
JNI攻略之七――操作對(duì)象的方法
AndroidJNI 通過(guò)C++調(diào)用JAVA
[深入理解Android卷一 全文
JNI官方規(guī)范中文版——使用JNI時(shí)容易出錯(cuò)的地方
Android系統(tǒng)移植與平臺(tái)開(kāi)發(fā)- JNI介紹
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服