![](/img/trans.png)
[英]Performance and Memory usage when Using std::string in Java JNI Programming
[英]Java JNI Programming : Actual usage of the Global References
在上一個問題中,我在JNI調用之間緩存了JNIEnv *。 從評論中,我知道它是無效的,這使我學習了JNI本地和全局引用。 我做了一些測試程序來理解它。 從測試程序中,我無法理解全局引用的使用。 因為本地引用本身在多個JNI調用之間正常工作。 我的測試程序有3個問題
下面給出測試代碼。
jni代碼:
jclass cls1, cls2, cls3;
jmethodID mth1, mth2, mth3;
jstring str1, str2;
jobject obj1, obj2, obj3;
JNIEXPORT void JNICALL Java_c_wrapperforjavaclass_clsNative_fnFindClass
(JNIEnv *env, jobject obj) {
if (cls1 == NULL || str1 == NULL || obj1 == NULL) {
cout << "Initializing new string object" << endl;
cls1 = env->FindClass("java/lang/String");
mth1 = env->GetMethodID(cls1, "<init>", "(Ljava/lang/String;)V");
str1 = env->NewStringUTF("Apple");
obj1 = env->NewObject(cls1, mth1, str1);
mth1 = env->GetMethodID(cls1, "length", "()I");
long i = (long) env->CallIntMethod(obj1, mth1);
cout << "Length = " << i << endl;
//env->DeleteLocalRef(cls1);
//env->DeleteLocalRef(str1);
//env->DeleteLocalRef(obj1);
} else {
cout << "String Object already initialized" << endl;
mth1 = env->GetMethodID(cls1, "length", "()I");
long i = (long) env->CallIntMethod(obj1, mth1);
cout << "Length = " << i << endl;
}
}
JNIEXPORT void JNICALL Java_c_wrapperforjavaclass_clsNative_fnGetExistingObject__Ljava_lang_String_2
(JNIEnv *env, jobject obj, jstring str) {
if (cls2 == NULL || obj2 == NULL) {
cout << "Initializing from existing string object" << endl;
cls2 = env->GetObjectClass(str);
obj2 = (jobject) env->NewLocalRef(str);
mth2 = env->GetMethodID(cls2, "length", "()I");
long i = (long) env->CallIntMethod(obj2, mth2);
cout << "Length = " << i << endl;
//env->DeleteLocalRef(cls2);
//env->DeleteLocalRef(obj3);
} else {
cout << "Object already initialized" << endl;
mth2 = env->GetMethodID(cls2, "length", "()I");
long i = (long) env->CallIntMethod(obj2, mth2);
cout << "Length = " << i << endl;
}
}
JNIEXPORT void JNICALL Java_c_wrapperforjavaclass_clsNative_fnGetExistingObject__Ljava_util_ArrayList_2
(JNIEnv *env, jobject obj, jobject lst) {
if (cls3 == NULL || obj3 == NULL) {
cout << "Initializing from existing ArrayList object" << endl;
cls3 = env->GetObjectClass(lst);
obj3 = (jobject) env->NewLocalRef(lst);
mth3 = env->GetMethodID(cls3, "size", "()I");
long i = (long) env->CallIntMethod(obj3, mth3);
cout << "Size = " << i << endl;
//env->DeleteLocalRef(cls3);
//env->DeleteLocalRef(obj3);
} else {
cout << "Object already initialized" << endl;
mth3 = env->GetMethodID(cls3, "size", "()I");
long i = (long) env->CallIntMethod(obj3, mth3);
cout << "Length = " << i << endl;
}
}
調用Java代碼(測試代碼):
a.fnFindClass();
a.fnFindClass();
String str = new String("Android OS");
a.fnGetExistingObject(str);
//Increasing the size
str = new String("Will modified string length get effect");
a.fnGetExistingObject(str);
ArrayList<Integer> al = new ArrayList<>();
al.add(1);al.add(2);al.add(3);
a.fnGetExistingObject(al);
al.add(4);al.add(5); //Increasing the size
a.fnGetExistingObject(al);
測試結果 :
Initializing new string object
Length = 5
String Object already initialized
Length = 5
Initializing from existing string object
Length = 10
Object already initialized
Length = 10
Initializing from existing ArrayList object
Size = 3
Object already initialized
Length = 5
提前致謝。
全局引用可防止垃圾收集器刪除相關對象。 也可能不僅僅因為另一個java對象具有對該對象的引用,或者因為垃圾收集器沒有在兩次調用之間的短時間內運行,所以也未收集該對象。 您不應依賴於此,而應保留對以后可能需要使用的所有內容的全局引用。
可以調整ArrayList的大小。 字符串是不可變的,始終需要為諸如substring或append之類的功能創建新的字符串。
我相信保持JNIEnv *的問題與線程安全性有關。 C ++代碼無法知道兩個不同的調用不是來自兩個不同的線程。 每個環境都需要附加到不同的線程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.