Android jni/ndk編程四:jni參考型別

來源:互聯網
上載者:User

標籤:多線程   崩潰   為我   uil   通過   class   執行   dcl   定義   

一.JNI參考型別

JNI支援三種類型的 opaque reference:local references, global references,和weak global references,下面我們將逐一探討。

local references

大部分JNI 函數都會建立LocalRef,如NewObject建立一個執行個體,並返回一個指向該執行個體的LocalRef。LocalRef只在本線程的 native method中有效. 一但native method返回,LocalRef 將被釋放。這意味著我們不能緩衝LocalRef來提高效率,因為native方法一旦返回,LocalRef將被釋放,緩衝起來也沒有用。 
我們已經知道了大部分JNI函數都會建立LocalRef,比如NewObject,FindClass等,與建立相對應的,我們可以有兩種方式讓LocalRef 無效:

  1. native method返回,JavaVM自動釋放LocalRef;
  2. 用DeleteLocalRef 主動釋放。 
    DeleteLocalRef的定義如下:
    void        (*DeleteLocalRef)(JNIEnv*, jobject);

DeleteLocalRef 主動釋放LocalRef是有意義的,如果我們記憶體特別緊張,而一個本地的方法有很多很耗記憶體的LocalRef,這個時候,在本地方法中及時釋放這些LocalRef可以緩解記憶體壓力。 
LocalRef只在建立該對象的線程中有效,因此我們無法在其他線程中使用共用LocalRef.

Global References

Global引用類似於全域變數,我們可以在多個native方法中使用,也可以在多個線程中使用。此外,Golbal引用會阻止GC回收。但是,與c總的全域變數不同的是,Golbal引用必須通過特定的函數手動建立和釋放。以下是相關函數的定義:

    jobject     (*NewGlobalRef)(JNIEnv*, jobject);    void        (*DeleteGlobalRef)(JNIEnv*, jobject);

使用舉例:

//1.首先定義一個靜態變數儲存Global引用static jclass stringClass = NULL;//2.獲得Local 引用jclass localRefCls = (*env)->FindClass(env,"java/lang/String");if (localRefCls == NULL) {return NULL; /* exception thrown */}//3.使用那個local引用建立全域引用stringClass = (*env)->NewGlobalRef(env, localRefCls);//4.及時釋放Local引用(*env)->DeleteLocalRef(env, localRefCls);

以上是常見的、簡單的建立Global引用的代碼流程,使用完以後,記得把它釋放掉,不然後記憶體流失了,因為Global引用是阻止GC的。

Weak Global References

所謂弱全域引用就是全域引用的另一個版本,既然它是全域引用,那麼它就具備了在多個線程中共用的能力,以及我們可以在單個線程的不同函數中都可以使用它。之所以說它弱是因為它無法阻止GC。前面我們說Global引用很強勢,它只能手動釋放,JVM虛擬機器不能自動GC它,但是Weak Global就會被記憶體回收行程回收,這就是它若的原因。 
Weak Global Ref用 NewGlobalWeakRef於DeleteGlobalWeakRef進行建立和刪除,多個本地方法調用過程中和多線程上下文中使用的特性與 GlobalRef相同。這兩個函數在jni.h中的定義如下:

    jweak       (*NewWeakGlobalRef)(JNIEnv*, jobject);    void        (*DeleteWeakGlobalRef)(JNIEnv*, jweak);

我們看到這裡又出現了一個新的類型:jweak,它其實就是jobject,只是名字不容而已:

typedef jobject         jweak;

用法舉例:

static jclass string= NULL;if (string == NULL) {    jclass local_string =    (*env)->FindClass(env, "java/lang/String");    if (myCls2Local == NULL) {        return; /* can’t find class */    }    string = NewWeakGlobalRef(env, local_string );    if (myCls2 == NULL) {        return; /* out of memory */    }}

由於Weak Global引用可能被記憶體回收行程回收,所以我們在使用它之前一定要判斷它是否為空白。如果空的話需要重新建立它,不為空白就繼續使用。

二.Comparing Reference

既然我們可以有多個引用,它可能是全域引用,弱全域引用或局部引用,我們怎麼判斷它是不是同一個引用呢?不用急,JNI已經為我們提供好了函數,我們可以直接用,其定義如下:

jboolean    (*IsSameObject)(JNIEnv*, jobject, jobject);

如果相通,返回JNI_TRUE, 否則返回JNI_FALSE。

三.引用管理

引用管理是為了較少記憶體使用量,提高代碼效率。JNI支援的三種引用各有各得用途,絕不能濫用。筆者水平有限,就不多廢話了,這裡主要講一下Local引用的管理。 
JNI提供了一組管理Local引用的函數:

    jint        (*PushLocalFrame)(JNIEnv*, jint);    jobject     (*PopLocalFrame)(JNIEnv*, jobject);

在進入本地方法時,調用一次 
PushLocalFrame,並在本地方法結束時調用 PopLocalFrame. 此對方法執行效率非常高,建議使用這對方法。 
一定保證該上下文出口只有一個,或每個return語句都做嚴格檢查是否調用了PopLocalFrame。因為如果忘記調用PopLocalFrame 可能會使JVM崩潰。 
用法舉例:

jobject hello(JNIEnv *env, jobject obj){jobject result;//進入函數後pushif ((*env)->PushLocalFrame(env, 10) < 0) {/* frame not pushed, no PopLocalFrame needed */return NULL;}...result = ...;if (...) {//認真檢查每一個函數的出口,絕不能忘記PopLocalFrameresult = (*env)->PopLocalFrame(env, result);return result;}...//正常返回前pop一下result = (*env)->PopLocalFrame(env, result);return result;}

Android jni/ndk編程四:jni參考型別

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.