<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                接續上篇[JNI開發系列④C語言調用構造方法](http://www.jianshu.com/p/b0403771944f) ### 前情提要 在上一篇中 , 我們了解到了 , 創建一個Java對象的幾個步驟: > 第一,`findClass`找到需要創建對象的類(全類名) 第二,得到構造方法的ID,構造方法名稱,統一使用`<init>` 第三,使用`NewObject`創建Java對象 當創建了這個類的對象之后 , 我們就可以使用這個類里面所提供的方法了 , 那么我們就可以在C中使用Java中其他對象的方法了 。 ### 數組引用的處理 在Java中 , 使用`new`關鍵字創建對象 , 創建之后我們就可以隨意使用這個對象 , 我們無需關心這個對象是什么時候被回收的 , 對象的回收已經托管到了JVM的GC , 由GC來幫我們回收無引用的對象 , 那么,我們使用JNI技術傳遞給C/C++的對像要怎么做處理呢 ? 將對象引用傳遞給C/C++時 , C/C++層就會持有Java對象 , 如果不進行妥善處理 , 對象多了就會出現內存泄漏問題 , 所有在C/C++層使用Java對象時 , 需要釋放這個引用 。 下面就來看看數組引用的處理: ```java // 對數組進行排序 private native void useArraySort(int[] array) ; public static void main(String[] args) { // Java數組在C中排序 int[] array = {1,60,20,10,4,90,23} ; jni.useArraySort(array); // 輸出 for (int i = 0; i < array.length; i++) { System.out.println("array == "+array[i]); } } ``` 將`array`對象傳遞給C , C中的變量將持有`array`這個引用 ```c // sort int compare(int* a, int* b) { return (*a) - (*b); } /*對數組進行排序*/ JNIEXPORT void JNICALL Java_com_zeno_jni_HelloJNI_useArraySort (JNIEnv *env, jobject jobj , jintArray jarray) { jint* arrayElemts = (*env)->GetIntArrayElements(env, jarray, NULL); jsize arraySize = (*env)->GetArrayLength(env, jarray); qsort(arrayElemts,arraySize,sizeof(jint),compare); // 釋放引用 , 因為數組和對象在java中都是引用 , 都會在堆內存中開辟一塊空間 , 但我們使用完對象之后 // 需要將引用釋放掉 , 不然會很耗內存 , 在一定程度上可能會造成內存溢出 。 //JNI_ABORT, Java數組不進行更新,但是釋放C/C++數組 //JNI_COMMIT,Java數組進行更新,不釋放C/C++數組(函數執行完,數組還是會釋放) (*env)->ReleaseIntArrayElements(env, jarray, arrayElemts, JNI_COMMIT); } ``` 內存示意圖: ![Java對象引用和C](http://upload-images.jianshu.io/upload_images/643851-12f6bb4ff09eacbe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 只要是Java對象 , 在C中都需要釋放,如String類型引用: ```c // String類型引用釋放 void (JNICALL *ReleaseStringUTFChars) (JNIEnv *env, jstring str, const char* chars); ``` 在C中創建的對象引用也需要進行引用釋放 ```c /*返回int類型的數組*/ JNIEXPORT jintArray JNICALL Java_com_zeno_jni_HelloJNI_getIntArray (JNIEnv *env, jobject jobj,jint len) { // 創建一個jint類型的數組 jintArray jArray = (*env)->NewIntArray(env, len); // 得到數組首個元素指針 jint* arrayElements = (*env)->GetIntArrayElements(env, jArray, NULL); // 指針運算 int i = 0; for (; i < len; i++) { arrayElements[i] = i; } // 同步 (*env)->ReleaseIntArrayElements(env, jArray, arrayElements, JNI_COMMIT); return jArray; } java code // 在C中生存數組 , 返回到Java中 private native int[] getIntArray(int len) ; int[] intArray = jni.getIntArray(20); for (int i = 0; i < intArray.length; i++) { System.out.println("int array === "+intArray[i]); } ``` > 為什么在C中創建的對象也需要釋放 ? 在上述代碼中 , 創建一個數組對象 , 并將引用傳遞給了Java層 , 將引用交給了Java之后 , C就需要釋放這個引用 , 不然會一直持有 , GC也不會回收這個對象 。 ### 引用的分級 在Java中引用也有強弱之分 , 使用`new`創建的對象就是強引用,也可以使用`WeakReference`將對象包裝成一個弱引用對象 。在C中也不列外 , C中也有一套`全局引用`,`局部引用`,`弱全局引用`等等 。 > 一 , 局部引用 ```c // 局部引用 // 作用:C使用到或自行創建Java對象,需要告知虛擬機在合適的時候回收對象 //局部引用,通過DeleteLocalRef手動釋放對象 //1.訪問一個很大的java對象,使用完之后,還要進行復雜的耗時操作 //2.創建了大量的局部引用,占用了太多的內存,而且這些局部引用跟后面的操作沒有關聯性 JNIEXPORT void JNICALL Java_com_zeno_jni_HelloJNI_localRef (JNIEnv *env, jobject jobj) { // 找到類 jclass dateClass = (*env)->FindClass(env, "java/util/Date"); // 得到構造方法ID jmethodID dateConstructorId = (*env)->GetMethodID(env, dateClass, "<init>", "()V"); // 創建Date對象 jobject dateObject = (*env)->NewObject(env, dateClass, dateConstructorId); // 創建一個局部引用 jobject dateLocalRef = (*env)->NewLocalRef(env, dateObject); // 省略N行代碼 // 不再使用對象 , 則通知GC回收對象 (*env)->DeleteLocalRef(env, dateLocalRef); // 因為dateObject也是局部對象,可以直接回收dateObject對象 //(*env)->DeleteLocalRef(env, dateObject); } ``` > 全局引用 ```c // 全局引用 // 定義全局引用 //共享(可以跨多個線程),手動控制內存使用 jstring globalStr; /*創建全局引用*/ JNIEXPORT void JNICALL Java_com_zeno_jni_HelloJNI_createGlobalRef (JNIEnv *env, jobject jobj) { jstring jStr = (*env)->NewStringUTF(env, "I want your love !"); // 創建一個全局引用 globalStr = (*env)->NewGlobalRef(env, jStr); } /*使用全局引用*/ JNIEXPORT jstring JNICALL Java_com_zeno_jni_HelloJNI_useGlobalRef (JNIEnv *env, jobject jobj) { return globalStr; } /*釋放全局引用*/ JNIEXPORT void JNICALL Java_com_zeno_jni_HelloJNI_deleteGlobalRef (JNIEnv *env, jobject jobj) { // 釋放全局引用 (*env)->DeleteGlobalRef(env, globalStr); } //弱全局引用 //節省內存,在內存不足時可以是釋放所引用的對象 //可以引用一個不常用的對象,如果為NULL,臨時創建 //創建:NewWeakGlobalRef,銷毀:DeleteGlobalWeakRef ``` > 引用緩存 ```c /*變量緩存*/ JNIEXPORT void JNICALL Java_com_zeno_jni_HelloJNI_variableCach (JNIEnv *env, jobject jobj) { // 找到String類 jclass stringClass = (*env)->FindClass(env, "java/lang/String"); // 得到構造方法ID jmethodID stringConstructorID = (*env)->GetMethodID(env, stringClass, "<init>", "()V"); // 創建String類 //// 緩存局部變量 , 只創建一次 , 關鍵字static static jobject stringObject = NULL; if (stringObject == NULL) { stringObject = (*env)->NewObject(env, stringClass, stringConstructorID); printf("------------- create String object --------------\n"); } /*jobject stringObject = (*env)->NewObject(env, stringClass, stringConstructorID); printf("------------- create String object --------------\n");*/ } ``` 引用的分級 , 上述代碼都有比較詳細的注釋 ,這里就不多加解釋了 , 說一下全局引用的簡單使用場景。 在開發中 , 我們常常需要初始化一些變量 , 進行全局使用 , 這里我們的全局引用就發揮了作用了 。 ```c // 初始化全局變量 //初始化全局變量,動態庫加載完成之后,立刻緩存起來 jstring initGlobalStr; JNIEXPORT void JNICALL Java_com_zeno_jni_HelloJNI_initVariable (JNIEnv *env, jclass jcls) { jstring initStr = (*env)->NewStringUTF(env, "create global init variable "); initGlobalStr = (*env)->NewGlobalRef(env, initStr); } /*訪問初始化全局變量*/ JNIEXPORT jstring JNICALL Java_com_zeno_jni_HelloJNI_accessInitGlobalVariable (JNIEnv *env, jobject jobj) { return initGlobalStr; } __java code__ static{ // 加載動態庫 System.loadLibrary("Hello_JNI") ; // 初始化全局變量 initVariable(); } ``` C中引用的分級和在Java中的類型 , 都需要在合適的環境使用 。 ### 結語 這是JNI系列的最后一篇 , 在這個系列中 , 我們大致了解了JNI的開發流程, 以及一些常用的API和技法 , 在下篇中 , 我們正式進入NDK開發 , 將我們在JNI中學到的應用起來 。NDK基礎過后 , 將會進入到C++語言的學習 , 我們要學會使用第三方C/C++庫 。 > 本系列由[動腦學院](http://www.dongnaoedu.com/)提供技術支持 , 動腦學院 -- 做一家受人尊重的企業,做一個令人尊敬的老師 ! ### 參考 [global_and_local_references](http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#global_and_local_references)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看