2010년 9월 27일 월요일

Local and Global References

 The JavaTM Native Interface Programmer's Guide and Specification 책의 Chapter 5의 내용의 일부를 요약한 내용입니다.
 원문 : http://java.sun.com/docs/books/jni/html/refs.html

 Local Reference
  • 대부분의 JNI 함수은 local reference를 생성한다. 예를 들어 NewObject JNI 함수는 새로운 인스턴스를 만들고 인스턴스의 local reference를 반환합니다.
  • local reference는 reference를 생성한 native 함수의 동적 context안에서만 유효합니다. 그리고, native 함수의 호출안에서 유효합니다.
  • local reference를 static 변수에 저장하면 안됩니다.
  • 아래의 예제에서 MyNewString 함수는 local reference의 사용이 잘못되었습니다. stringClass는 static 변수이기 때문에 NewObject로 생성하면 안됩니다. NewGlobalObject로 생성하거나 stringClass는 지역변수가 되어야 합니다.
    /* This code is illegal */
    jstring
    MyNewString(JNIEnv *env, jchar *chars, jint len)
    {
     static jclass stringClass = NULL;
     jmethodID cid;
     jcharArray elemArr;
     jstring result;
    
     if (stringClass == NULL) {
      stringClass = (*env)->FindClass(env,"java/lang/String");
      if (stringClass == NULL) {
       return NULL; /* exception thrown */
      }
     }
     
     /* It is wrong to use the cached stringClass here,
     because it may be invalid. */
     cid = (*env)->GetMethodID(env, stringClass, "", "([C)V");
     ...
     elemArr = (*env)->NewCharArray(env, len);
     ...
     result = (*env)->NewObject(env, stringClass, cid, elemArr);
     (*env)->DeleteLocalRef(env, elemArr);
     return result;
    }
    
    • 아래의 코드에서 MyNewString 함수가 local reference를 반환한다면 문제가 발생할 수 있습니다.
    JNIEXPORT jstring JNICALL
     Java_C_f(JNIEnv *env, jobject this)
     {
         char *c_str = ...;
         ...
         return MyNewString(c_str);
     }
    
    • Local reference는 2가지 방법으로 free가 됩니다. native 함수가 반환되기전에 virtual machine이 자동으로 함수가 수행되는 동안 생성된 모든 local reference를 free합니다. 또한, 프로그래머가 DeleteLocalRef 함수를 명시적으로 호출하여 특정 local reference를 free 할 수 있습니다.
    • Local reference는 무효화(invalidated)되기전까지 가비지 컬렉션(Garbage Collection, GC)되지 않습니다.
    • DeleteLocalRef 함수로 무효화된 Local reference는 즉시 가비지 컬렉션됩니다.


    Global Reference
    • Global reference는 여러 native 함수에서 사용할 수 있습니다(전역변수처럼 사용된다능~).
    • 프로그래머가 free를 하기 전까지 여러 thread와 native 함수에서 사용될 수 있습니다.
    • Global reference도 local reference와 같이 무효화되기전까지는 가비지 컬렉션되지 않습니다.
    • Global reference는 NewGlobalRef JNI 함수로만 생성할 수 있습니다.
    • DeleteGlobalRef 함수는 global reference를 해제할 때 사용한다. 만약 DeleteGlobalRef 함수의 호출이 실패한다면, Java VM은 reference의 object를 가비지 컬렉션하지 않는다. object가 시스템에서 더 이상 사용되지 않더라도...
    • 아래는 Global reference의 사용의 예입니다.
    jstring
     MyNewString(JNIEnv *env, jchar *chars, jint len)
     {
         static jclass stringClass = NULL;
         ...
         if (stringClass == NULL) {
             jclass localRefCls =
                 (*env)->FindClass(env, "java/lang/String");
             if (localRefCls == NULL) {
                 return NULL; /* exception thrown */
             }
             /* Create a global reference */
             stringClass = (*env)->NewGlobalRef(env, localRefCls);
             
             /* Is the global reference created successfully? */
             if (stringClass == NULL) {
                 return NULL; /* out of memory exception thrown */
             }
         }
         ...
     }


    Weak Global Reference
    • Weak global reference는 NewGlobalWeakRef 함수와 DeleteGlobalWeakRef 함수로 생성하고 해제할 수 있습니다.
    • Weak global reference는 globa reference와 동일하게 여러 thread와 native 함수에서 사용될 수 있습니다.
    • global reference와 다른 점은 가비지 컬렉션으로부터 기본 object를 유지하지 않습니다.(이게 무슨 말이냐? 가비지 컬렉션이 될 수 있다는 말인데 가비지 컬렉션이 언제되느냐가 weak global reference의 핵심이다. global reference는 DeleteGlobalRef 함수를 호출를 호출하지 않는한 object는 가비지 컬렉션되지 않는다.)
    • 아래 예제에서 mypkg.MyCls class이 f 함수는 mypkg.MyCls2 클래스 object의 reference를 저장을 해야 한다. weak global reference에 저장된 class는 mypkg.MyCls2 클래스를 여전히 unload된채로 둔다.(??, 뭥미? 해석이 안됨. ㅠㅠ)
      • Java_mypkg_MyCls_f 함수는 MyCls class의 native member method이다.
    JNIEXPORT void JNICALL
     Java_mypkg_MyCls_f(JNIEnv *env, jobject self)
     {
         static jclass myCls2 = NULL;
         if (myCls2 == NULL) {
             jclass myCls2Local =
                 (*env)->FindClass(env, "mypkg/MyCls2");
             if (myCls2Local == NULL) {
                 return; /* can't find class */
             }
             myCls2 = NewWeakGlobalRef(env, myCls2Local);
             if (myCls2 == NULL) {
                 return; /* out of memory */
             }
         }
         ... /* use myCls2 */
     }
    
    • MyCls와 MyCls2는 같은 life time을 가진다고 가정한다.(예를 들어, 두 클래스는 같은 class loader에 의해서 load 되었을것이다.)
    • 그래서, 우리는 MyCls와 MyCls의 native method 구현인 Java_mypkg_MyCls_f가 사용인채로 남아 있는 동안에는 MyCls2가 언제 unload 될지, 그리고 나중에 언제 reload 될지에 대한 상황을 고려하지 않는다. 
    • 만약 myCls2가 unloade가 발생했다면, 우리는 cached weak reference가 여전히 살아있는 class object를 가리키고 있는지, 이미 GC가 된 object를 가리키고 있는지 반드시 검사해야만 한다.
    Comparing Reference
    • 2개의 Local, global, or weak global reference가 있을 때, reference에 object가 같은지 검사하는 하는 방법은 아래와 같다.
      • (*env)->IsSameObject(env, obj1, obj2)
      • JNI_TRUE(or 1)이 반환되면, 두 reference는 같은 object를 참조한다.
      • JNI_FALSE(or 0)이 반환되면, 두 reference는 다른 object를 참조한다.
    •  Weak global reference는 다른 규칙이 있다. weak reference가 null object를 참조할 경우에는 object는 GC가 되었다는 것이다.
      • (*env)->IsSameObject(env, wobj, NULL)
      • 반환값이 JNI_TRUE이면 weak reference가 참조하는 object는 GC가 되었다는 것이다.
      • 반환값이 JNI_FALSE면 weak reference는 여전히 유효한(살아있는) object를 참조한다.

    댓글 없음:

    댓글 쓰기