[JNI]JNI函數接口大全

本文基於JNI函數接口的常用用法整理了AndroidStudio工程實例,便於大家學習和記憶。

這篇文章是基於參考資料[1]中第十三章"JNI Functions"整理的,TestCode涵蓋了以下用法:

 

[0 整理思路]

由參考資料[1]中第十三章"JNI Functions"中,我們可以將jni functions大致分爲如下四大類:

1 由VM直接導出的調用接口函數

2 JavaVM接口

3 Native庫中定義的函數

4 JNIEnv接口

我們將按照如上順序,學習jni functions.

 

 

[1 由VM直接導出的調用接口函數]

注意:這三個接口只是由VM爲JNI導出的三個符號,一般不用用戶調用!

1 JNI_GetDefaultJavaVMInitArgs

jint JNI_GetDefaultJavaVMInitArgs(void*);

返回Java虛擬機實現的默認配置。

 

2 JNI_CreateJavaVM

jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);

加載並初始化一個虛擬機實例。

 

3 JNI_GetCreatedJavaVMs

jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*);

 

 

[2 JavaVM接口]

1 DestroyJavaVM      

jint DestroyJavaVM()

卸載JavaVM並釋放它的資源。

 

2 AttachCurrentThread

jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)

綁定當前線程(一般是子線程)到一個虛擬機實例。

 

3 DetachCurrentThread

jint DetachCurrentThread()

使得當前線程脫離一個虛擬機實例。

 

4 GetEnv

jint GetEnv(void** env, jint version)

(1)用來檢查當前線程是否綁定到給定的虛擬機實例,env設置爲NULL,返回錯誤JNI_EDETACHED.

(2)用來獲取其他接口,如JNIEnv的interfaces.

 

 

[3 Native庫中定義的函數]

1 JNI_OnLoad

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved);

當虛擬機加載一個native庫時,調用JNI_OnLoad接口。即System.loadLibrary會調用JNI_OnLoad接口。獲取JavaVM對象。

 

2 JNI_OnUnload

JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved);

當虛擬機卸載一個native庫時,調用JNI_OnUnload接口。

 

 

[4 JNIEnv接口]

(1)Version Information

1 GetVersion

jint GetVersion()

返回JNIEnv interface的版本號

 

(2)Class and Interface Operations

1 DefineClass 

jclass DefineClass(const char *name, jobject loader, const jbyte* buf, jsize bufLen)

從一個jbyte* buffer裏定義一個類

 

2 FindClass

jclass FindClass(const char* name)

返回一個類的引用

 

3 GetSuperclass

jclass GetSuperclass(jclass clazz)

返回基類,除了java.lang.Object類(因爲java.lang.Object是最基類)

 

(3)Exceptions

1 FatalError

void FatalError(const char* msg)

打印信息並終止當前虛擬機實例

 

2 ExceptionCheck

jboolean ExceptionCheck()

檢查當前線程是否發生了異常,若有異常返回JNI_TRUE,否則返回JNI_FALSE

 

3 ExceptionDescribe

void ExceptionDescribe()

JNI層打印異常的堆棧信息!!!

 

4 ExceptionClear

void ExceptionClear()

清除異常堆棧信息

 

5 Throw and ThrowNew

jint Throw(jthrowable obj)

丟棄一個現有的異常對象,在當前線程觸發一個新的異常

jint ThrowNew(jclass clazz, const char* message)

在當前線程觸發一個異常,並自定義輸出異常信息

 

6 ExceptionOccurred

jthrowable ExceptionOccurred()

檢查當前線程是否發生了異常,若有異常返回該異常的引用,否則返回NULL

 

(4)Global and Local References

1 NewGlobalRef,DeleteGlobalRef

jobject NewGlobalRef(jobject obj)

void DeleteGlobalRef(jobject globalRef)

(1)創建:

調用NewGlobalRef,基於全局引用,弱全局引用,局部引用創建

(2)會阻止GC回收所引用的對象:

只有手動釋放全局引用後,垃圾回收機制纔可以回收

(3)能跨函數使用,能跨線程使用:

(4)釋放:

(i)自動釋放:無自動釋放

(ii)手動釋放:(*env)->DeleteGlobalRef(env,g_cls_string)

 

2 NewWeakGlobalRef,DeleteWeakGlobalRef

jweak NewWeakGlobalRef(jobject obj)

void DeleteWeakGlobalRef(jweak obj)

(1)創建:

調用NewWeakGlobalRef,基於局部引用或全局引用創建

(2)不會阻止GC回收所引用的對象:

GC認爲應該回收它的時候(比如內存緊張的時候)會進行自動回收,從而釋放全局弱引用

(3)能跨函數使用,能跨線程使用:

(4)釋放:

(i)自動釋放:在GC認爲應該回收它的時候(比如內存緊張的時候)會進行自動回收,釋放全局弱引用

(ii)手動釋放:(*env)->DeleteWeakGlobalRef(env,g_cls_string)

 

3 NewLocalRef,DeleteLocalRef

jobject NewLocalRef(jobject ref)

void DeleteLocalRef(jobject localRef)

(1)創建

調用NewLocalRef或其他JNI接口(FindClass、NewObject、NewCharArray)創建。

(2)會阻止GC回收所引用的對象

只有釋放局部引用後GC纔可以回收

(3)不能跨函數使用,不能跨線程使用

(4)釋放

(i)自動釋放:函數返回後局部引用的當前對象會被GC自動釋放,所以局部引用是有內存溢出的風險的!!!

例如:在函數體內有循環,循環裏New局部引用會出現內存溢出!!!

JNIEXPORT void JNICALL f(JNIEnv *env,jobject obj){

    for(int i=0;i<len;i++){

        jobject strLocalref = env->NewLocalRef(strObject);

        ...

        //如果沒有手動釋放strLocalref ,只有最後一個strLocalref 會被GC自動釋放,其餘strLocalref會出現native內存泄漏

        //env->DeleteLocalRef(strLocalref );

    }

}

(ii)手動釋放:(*env)->DeleteLocalRef(env,local_ref)

 

(5)Object Operations

1 GetObjectClass

jclass GetObjectClass(jobject obj)

返回一個對象對應的類

 

2 IsInstanceOf

jboolean IsInstanceOf(jobject obj, jclass clazz)

檢查一個對象是否是一個類的實例

 

3 NewObject

jobject NewObject(jclass clazz, jmethodID methodID, ...)

分配對象空間並構造該對象

 

4 AllocObject

jobject AllocObject(jclass clazz)

分配一個未初始化的對象

 

(6)Instance Field Access

1 GetFieldID

jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)

獲取類的成員域ID

 

2 Get<Type>Field,Set<Type>Field

jint GetIntField(jobject obj, jfieldID fieldID)

根據成員域ID獲取類成員

void SetIntField(jobject obj, jfieldID fieldID, jint value)

根據成員域ID設置類成員

 

(7)Static Field Access

1 GetStaticFieldID

jfieldID GetStaticFieldID(jclass clazz, const char* name, const char* sig)

獲取類的靜態成員域ID

 

2 GetStatic<Type>Field,SetStatic<Type>Field

jint GetStaticIntField(jclass clazz, jfieldID fieldID)

根據成員域ID獲取類靜態成員

void SetStaticIntField(jclass clazz, jfieldID fieldID, jint value)

根據成員域ID設置類靜態成員

 

(8)Instance Method Calls

1 GetMethodID

jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)

獲取一個類方法的方法ID

 

2 Call<Type>Method

jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);

調用類方法

 

(9)Static Method Calls

1 GetStaticMethodID

jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig)

獲取一個類靜態方法的方法ID

 

2 CallStatic<Type>Method

jint        (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...);

調用類靜態方法

 

(10)String Operations

char*(1字節)~UTF-8字符串

jchar*(2字節)~Unicode字符串

 

1 NewString

jstring NewString(const jchar* unicodeChars, jsize len)

通過jchar*創建一個jstring對象

 

2 NewStringUTF

jstring NewStringUTF(const char* bytes)

通過char*創建一個jstring對象

 

3 GetStringLength

jsize GetStringLength(jstring string)

返回jstring的長度

 

4 GetStringUTFLength

jsize GetStringUTFLength(jstring string)

返回jstring的長度

 

5 GetStringChars/ReleaseStringChars

const jchar* GetStringChars(jstring string, jboolean* isCopy)

通過jstring獲取jchar*指針

void ReleaseStringChars(jstring string, const jchar* chars)

釋放jstring對應的jchar*指針

 

6 GetStringUTFChars/ReleaseStringUTFChars

const char* GetStringUTFChars(jstring string, jboolean* isCopy)

通過jstring獲取char*指針

void ReleaseStringUTFChars(jstring string, const char* utf)

釋放jstring對應的char*指針

 

7 GetStringCritical/ReleaseStringCritical

const jchar* GetStringCritical(jstring string, jboolean* isCopy)

通過jstring獲取jchar*指針

void ReleaseStringCritical(jstring string, const jchar* carray)

釋放jstring對應的jchar*指針

 

8 GetStringRegion/GetStringUTFRegion

void GetStringRegion(jstring str, jsize start, jsize len, jchar* buf)

將jstring對象拷貝到jchar*內存

void GetStringUTFRegion(jstring str, jsize start, jsize len, char* buf)

將jstring對象拷貝到char*內存

 

(11)Array Operations

1 GetArrayLength

jsize GetArrayLength(jarray array)

返回數組元素個數

 

2 NewObjectArray

jobjectArray NewObjectArray(jsize length, jclass elementClass,jobject initialElement)

創建對象數組

 

3 New<Type>Array

jintArray NewIntArray(jsize length)

創建基本類型數組(int,char...)

 

4 GetObjectArrayElement/SetObjectArrayElement

jobject GetObjectArrayElement(jobjectArray array, jsize index)

獲取對象數組元素

void SetObjectArrayElement(jobjectArray array, jsize index, jobject value)

設置對象數組元素

 

5 Get<Type>ArrayElements/Release<Type>ArrayElements

jint* GetIntArrayElements(jintArray array, jboolean* isCopy)

獲取基本類型數組內存指針

void ReleaseIntArrayElements(jintArray array, jint* elems,jint mode)

釋放基本類型數組內存

 

6 Get<Type>ArrayRegion/Set<Type>ArrayRegion

void GetIntArrayRegion(jintArray array, jsize start, jsize len,jint* buf)

拷貝jintArray到jint*

void SetIntArrayRegion(jintArray array, jsize start, jsize len,const jint* buf)

拷貝const jint*到jintArray

 

(12)Native Method Registration

1 RegisterNatives/UnregisterNatives

jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)

註冊native方法

jint UnregisterNatives(jclass clazz)

註銷native方法

 

(13)Monitor Operations

1  MonitorEnter

jint MonitorEnter(jobject obj)

進入臨界區

2  MonitorExit

jint MonitorExit(jobject obj)

退出臨界區

 

(14)JavaVM Interface

1  GetJavaVM

jint GetJavaVM(JavaVM** vm)

獲取當前虛擬機JavaVM指針

 

 

[5 參考資料]

[1]The Java™ Native Interface Programmer’s Guide and Specification.pdf

[2]JNI/NDK開發指南

https://blog.csdn.net/xyang81/article/category/2759987

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章