관리 메뉴

드럼치는 프로그래머

[JNI/NDK] JNI 사용시 메모리 관리 본문

★─Programing/☆─JNI | NDK

[JNI/NDK] JNI 사용시 메모리 관리

드럼치는한동이 2013. 5. 31. 13:31

갑자기 잘되던 프로그램이 안된다...

당황하다가 다시 마음을 잡고 천천히 디버깅 해보았다.

Native와 JAVA 사이에 연결되는 함수가 호출되다가 죽는다.

아래와 같이 반복문이 15회정도 반복되는 함수였다.

float correctCount = 0.0f; for( int i = 0; i < 30; i++ ) { if( jni_GetPUnlocked( s, i ) == true ) { correctCount++; } }

 

 

jni_GetPUnlocked 함수는 JAVA함수를 C언어로 읽어들여 체크하는 함수였다.
함수 내용은 아래와 같다.

bool jni_GetPUnlocked(int game, int question) {     JNIEnv *env;     jclass jNativesCls;     bool pUnlocked = false;     if ( !g_VM ) { return pUnlocked;     }     g_VM->AttachCurrentThread ( &env, NULL);     jNativesCls = env->FindClass("com/jni/Natives");     if ( jNativesCls == 0 ) { return pUnlocked;     }     jmethodID mid = env->GetStaticMethodID(jNativesCls , "GetPUnlocked" , "(II)Z");     if (mid) { pUnlocked = env->CallStaticBooleanMethod(jNativesCls , mid , game , question ); data.pUnlocked[game][question] = pUnlocked;     }     return pUnlocked; }

문제가 없어보인다.
기존에 잘 작동 했었고;;

하지만 갑자기 아래와 같은 에러 메세지를 뱉어내고 프로그램이 죽었다.


04-19 09:27:16.062: WARN/dalvikvm(6702): ReferenceTable overflow (max=512)
04-19 09:27:16.062: WARN/dalvikvm(6702): Last 10 entries in JNI local reference table:
04-19 09:27:16.062: WARN/dalvikvm(6702): 502: 0x40568828 cls=Ljava/lang/Class; 'Lcom/jni/Natives;' (212 bytes)
04-19 09:27:16.062: WARN/dalvikvm(6702): 503: 0x40568828 cls=Ljava/lang/Class; 'Lcom/jni/Natives;' (212 bytes)
04-19 09:27:16.062: WARN/dalvikvm(6702): 504: 0x40568828 cls=Ljava/lang/Class; 'Lcom/jni/Natives;' (212 bytes)
04-19 09:27:16.062: WARN/dalvikvm(6702): 505: 0x40568828 cls=Ljava/lang/Class; 'Lcom/jni/Natives;' (212 bytes)
04-19 09:27:16.062: WARN/dalvikvm(6702): 506: 0x40568828 cls=Ljava/lang/Class; 'Lcom/jni/Natives;' (212 bytes)
04-19 09:27:16.062: WARN/dalvikvm(6702): 507: 0x40568828 cls=Ljava/lang/Class; 'Lcom/jni/Natives;' (212 bytes)
04-19 09:27:16.062: WARN/dalvikvm(6702): 508: 0x40568828 cls=Ljava/lang/Class; 'Lcom/jni/Natives;' (212 bytes)
04-19 09:27:16.062: WARN/dalvikvm(6702): 509: 0x40568828 cls=Ljava/lang/Class; 'Lcom/jni/Natives;' (212 bytes)
04-19 09:27:16.062: WARN/dalvikvm(6702): 510: 0x40568828 cls=Ljava/lang/Class; 'Lcom/jni/Natives;' (212 bytes)
04-19 09:27:16.062: WARN/dalvikvm(6702): 511: 0x40568828 cls=Ljava/lang/Class; 'Lcom/jni/Natives;' (212 bytes)
04-19 09:27:16.062: WARN/dalvikvm(6702): JNI local reference table summary (512 entries):
04-19 09:27:16.062: WARN/dalvikvm(6702): 510 of Ljava/lang/Class; 212B (1 unique)
04-19 09:27:16.062: WARN/dalvikvm(6702): 1 of Ljava/lang/Class; 356B
04-19 09:27:16.062: WARN/dalvikvm(6702): 1 of Ljava/lang/String; 28B
04-19 09:27:16.062: WARN/dalvikvm(6702): Memory held directly by tracked refs is 596 bytes
04-19 09:27:16.062: ERROR/dalvikvm(6702): Failed adding to JNI local ref table (has 512 entries)


대충봐도 메모리 문제로 오버플로우 났다 이런것이였다.

음 먼가 모르던 메모리 관리를 해야 하는건가? 메모리 대여폭을 증가시키는 설정값이라도 있나? 의문이 들었다.

열심히 구글링 한 결과 아래 웹페이지를 찾을수 있었다.

http://java.sun.com/docs/books/jni/html/refs.html#27567


대충 앞부분만 봐도 JNI를 이용할때 메모리 관리를 간과하기 쉽다고 잘하란다=ㅁ=;

위 Native함수를 아래와 같이 수정하니 정상 동작한다.
bool jni_GetPUnlocked(int game, int question)
{
 JNIEnv *env;
 jclass jNativesCls;
 bool pUnlocked = false;
 if ( !g_VM ) {
  return pUnlocked;
 }
 g_VM->AttachCurrentThread ( &env, NULL);
 jNativesCls = env->FindClass("com/jni/Natives");
 if ( jNativesCls == 0 ) {
  return pUnlocked;
 }
 jmethodID mid = env->GetStaticMethodID(jNativesCls
  , "GetPUnlocked"
  , "(II)Z");
 if (mid) {
  pUnlocked = env->CallStaticBooleanMethod(jNativesCls
   , mid
   , game
   , question );
  data.pUnlocked[game][question] = pUnlocked;
 }
 // 수정된 부분
 env->DeleteLocalRef( jNativesCls );
 return pUnlocked;
}
Native에서 생성한 지역변수에 대한 메모리 관리를 해야 한다는 내용이였다.

예전 책에서 봤던 코드는 env->FindClass("com/jni/Natives"); 로 호출하여 받아온 변수를 전역변수로 하나 들고
다시 호출 안하고 했었는데 전역변수 두기가 번거로워서 지역변수로 매번 얻어왔던게 화근이였다.

매번 얻어와도 해제만 잘해줬으면 되는데...알리가 있나-ㅁ-;;

새벽까지 삽질하다가 자고 일어나니 바로 찾아지는 이 기쁨

다행이다-ㅁ-;

[출처] http://dunkhoon.tistory.com/34

Comments