• 缓存字段ID和方法ID


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

    使用时缓存
    字段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:\n"); 
      
         jstr = (*env)->GetObjectField(env, obj, fid_s); 
         str = (*env)->GetStringUTFChars(env, jstr, NULL); 
         if (str == NULL) { 
             return; /* out of memory */ 
         } 
         printf("  c.s = \"%s\"\n", 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); 
     } 

     同样的思想,我们也可以缓存 java.lang.String 的构造方法的ID:

     jstring MyNewString(JNIEnv *env, jchar *chars, jint len) 
     { 
         jclass stringClass; 
         jcharArray elemArr; 
         static jmethodID cid = NULL; 
         jstring result; 
      
         stringClass = (*env)->FindClass(env, "java/lang/String"); 
         if (stringClass == NULL) { 
             return NULL; /* exception thrown */ 
         } 
         
         /* Note that cid is a static variable */ 
         if (cid == NULL) { 
             /* Get the method ID for the String constructor */ 
             cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V"); 
             if (cid == NULL) { 
                 return NULL; /* exception thrown */ 
             } 
         } 
         
         /* Create a char[] that holds the string characters */ 
         elemArr = (*env)->NewCharArray(env, len); 
         if (elemArr == NULL) { 
             return NULL; /* exception thrown */ 
         } 
         (*env)->SetCharArrayRegion(env, elemArr, 0, len, chars); 
      
         /* Construct a java.lang.String object */ 
         result = (*env)->NewObject(env, stringClass, cid, elemArr); 
      
         /* Free local references */ 
         (*env)->DeleteLocalRef(env, elemArr); 
         (*env)->DeleteLocalRef(env, stringClass); 
         return result; 
     } 

     当MyNewString方法第一次被调用时,我们计算 java.lang.String 的构造方法的ID,并存储在静态变量 cid中。

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

    class InstanceMethodCall { 
         private static native void initIDs(); 
         private native void nativeMethod(); 
         private void callback() { 
             System.out.println("In Java"); 
         } 
         public static void main(String args[]) { 
             InstanceMethodCall c = new InstanceMethodCall(); 
             c.nativeMethod(); 
         } 
         static { 
             System.loadLibrary("InstanceMethodCall"); 
             initIDs(); 
         } 
     } 

    initIDs方法简单地计算并缓存方法ID:

    jmethodID MID_InstanceMethodCall_callback; 
      
    JNIEXPORT void JNICALL  Java_InstanceMethodCall_initIDs(JNIEnv *env, jclass cls) 
     { 
         MID_InstanceMethodCall_callback = (*env)->GetMethodID(env, cls, "callback", "()V"); 
     } 

    VM进行静态初始化时在调用任何方法前调用 initIDs,这样方法ID 就被缓存了全局变量中,本地方法的实现就不必再进行 ID计算:

    JNIEXPORT void JNICALL Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj) 
     { 
         printf("In C\n"); 
         (*env)->CallVoidMethod(env, obj,MID_InstanceMethodCall_callback); 
     } 

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

  • 相关阅读:
    2.6、实战案例(三)
    2.5、实战案例(二)
    2.4、实战案例(一)
    2.3、视频采集(二):分辨率、摄像头切换、帧率、滤镜
    2.2、视频采集(一):初步采集
    2.1、列举媒体设备
    1.0、本章导读
    linux 下搭建vsftpd
    解决.net core 3.1跨域问题
    SQLServer for linux安装
  • 原文地址:https://www.cnblogs.com/lijunamneg/p/2829052.html
Copyright © 2020-2023  润新知