• JNI由浅入深_8_JNI缓存字段和方法ID


    获取字段ID和方法ID时,需要用字段、方法的名字和描述符进行一个检索。检索过程相对比较费时,因此本节讨论用缓存技术来减少这个过程带来的消耗。缓存字段ID和方法ID的方法主要有两种。两种区别主要在于缓存发生的时刻,是在字段ID和方法ID被使用的时候,还是定义字段和方法的类静态初始化的时候。

    1、使用时缓存

    字段ID和方法ID可以在字段的值被访问或者方法被回调的时候缓存起来。下面的代码中把字段ID存储在静态变量当中,这样当本地方法被重复调用时,不必重新搜索字段ID。

    JNIEXPORT void JNICALL 
     Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj)
     {
         static jfieldID fid_s = NULL; /* cached field ID for s */
     
         jclass cls = (*env)->GetObjectClass(env, obj);
         jstring jstr;
         const char *str;
     
         if (fid_s == NULL) {
             fid_s = (*env)->GetFieldID(env, cls, "s", 
                                        "Ljava/lang/String;");
             if (fid_s == NULL) {
                 return; /* exception already thrown */
             }
         }
     
         printf("In C:
    ");
     
         jstr = (*env)->GetObjectField(env, obj, fid_s);
         str = (*env)->GetStringUTFChars(env, jstr, NULL);
         if (str == NULL) {
             return; /* out of memory */
         }
         printf("  c.s = "%s"
    ", str);
         (*env)->ReleaseStringUTFChars(env, jstr, str);
     
         jstr = (*env)->NewStringUTF(env, "123");
         if (jstr == NULL) {
             return; /* out of memory */
         }
         (*env)->SetObjectField(env, obj, fid_s, jstr);
     }

    2、初始化缓存

    许多情况下,在字段ID和方法ID被使用前就初始化是很方便的。VM在调用一个类的方法和字段之前,都会执行类的静态初始化过程,所以在静态初始化该类的过程中计算并缓存字段ID和方法ID是个不错的选择。

    例如,为了缓存InstanceMethodCall.callback的方法ID,我们引入了一个新的本地方法initIDs,这个方法在InstanceMethodCall的静态初始化过程中被调用。

    /**
     *  缓存ID
     */
    jmethodID callbackStatic;
    
    
    JNIEXPORT void JNICALL Java_com_example_jniandroid_service_CFunction_callJniNative2(
    		JNIEnv * env, jobject obj) {
    	LOGI("缓存了id...");
    	(*env)->CallStaticVoidMethod(env, obj, callbackStatic);
    }
    
    
    JNIEXPORT void JNICALL Java_com_example_jniandroid_service_CFunction_initIDS(
    		JNIEnv * env, jobject obj) {
    	//调用静态方法
    	jclass cls = (*env)->GetObjectClass(env, obj);
    	callbackStatic = (*env)->GetStaticMethodID(env, cls, "callbackStatic", "()V");
    }

    两种缓存ID的方式之间的对比

    如果JNI程序员不能控制方法和字段所在的类的源码的话,在使用时缓存是个合理的方案。例如在MyNewString当中,我们不能在String类中插入一个initIDs方法。

    比起静态初始时缓存来说,使用时缓存有一些缺点:

    1、使用时缓存的话,每次使用时都要检查一下。

    2、方法ID和字段ID在类被unload时就会失效,如果你在使用时缓存ID,你必须确保只要本地代码依赖于这个ID的值,那么这个类不被会unload(下一章演示了如何通过使用JNI函数创建一个类引用来防止类被unload)。另一方面,如果缓存发生在静态初始化时,当类被unload和reload时,ID会被重新计算。

    因此,尽可能在静态初始化时缓存字段ID和方法ID。


  • 相关阅读:
    BUUCTF--[GUET-CTF2019]number_game
    36D杯CTF Re WP
    BUUCTF--[GWCTF 2019]re3
    虎符网络安全赛道 Re Game
    Python ZIP压缩文件破解
    合唱队, 华为
    字符串排序, 华为
    称砝码, 华为
    迷宫问题, 华为
    Sudoku , 华为
  • 原文地址:https://www.cnblogs.com/lbangel/p/4335857.html
Copyright © 2020-2023  润新知