관리 메뉴

드럼치는 프로그래머

[JNI/NDK] ReleaseByteArrayElements 고찰 본문

★─Programing/☆─JNI | NDK

[JNI/NDK] ReleaseByteArrayElements 고찰

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

제목 : jbyteArray2cstr 메모리 해제가 안됩니다.
글쓴이: 정완호(guest) 2005/05/16 18:17:13 조회수:776 줄수:43
JNI 프로그래밍을 하다보면 
김덕태님의 작성하신 NativeStringUtil.c 의 소스를 사용하게 됩니다.
그런데 이함수가 문제가 있습니다. 
malloc을 하고 free하는 부분이 없네요 

(*env)->ReleaseByteArrayElements 에서 JVM이 자동으로 해주는거 같은데 
JVM이 신뢰가 가지 않습니다.

char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes )
{
    size_t len = (*env)->GetArrayLength(env, javaBytes);
    jbyte *nativeBytes = (*env)->GetByteArrayElements(env, javaBytes, 0);
    char *nativeStr = malloc(len+1);

    memcpy( nativeStr, nativeBytes, len );
    nativeStr[len] = '\0';
    (*env)->ReleaseByteArrayElements(
        env, javaBytes, nativeBytes, JNI_ABORT);
    return nativeStr;
}

그래서 위의 함수를 아래와 같이 바꾸어 보았읍니다.

char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes )
{
    
    size_t len = (*env)->GetArrayLength(env, javaBytes);
    jbyte *nativeBytes = (*env)->GetByteArrayElements(env, javaBytes, 0);

 =>   char nativeStr[10000];  /* - 최대 사이즈를 10000바이트로 보고 */
 =>   memset( nativeStr, 0x00, sizeof( nativeStr ) );

    memcpy( nativeStr, nativeBytes, len );
    nativeStr[len] = '\0';
    (*env)->ReleaseByteArrayElements(
        env, javaBytes, nativeBytes, JNI_ABORT);
    return nativeStr;
}

malloc을 빼고 그냥 버퍼로 설정을 했습니다. 
그냥 봐서는 문제가 없이 돌아갈거 같아서 컴파일을 했는데 
실행시에 문제가 발생합니다. 어떻게 하면 될까요?
제목 : Re: 기본적인 이해가 필요합니다.[정정]
글쓴이: 사랑전쟁(lovewar) 2005/05/17 09:31:57 조회수:2093 줄수:34
jbyteArray2cstr 함수의 기능을 이해함으로써 이 로직를 이해할 수 있습니다.
또한 C의 메모리관리 문제(프로그래머의 개입)를 이해함으로써 이로직을 이해할 수 있습니다.

이 함수의 기능은 JVM에 있는 자료(jbyteArray)를 C의 문자열(char *)로 생성해 주는 
함수로 이해했습니다.

문자열로 생성한다는 것은 메모리를 공유하여 생성할 것인지 아니면 각 문자열마다
개별적으로 메모리를 사용할 것인지의 문제를 앉고 있습니다.

즉, 정완호님이 작성하신 코드는 메모리를 공유하는(char nativeStr[10000]) 것입니다.
또한 C언어에서 자동변수를 반환하기 때문에 위험한 코드입니다.  //추가된 라인

-- 정정 전 --
ReleaseByteArrayElements() 메소드는 JVM에 있는 메모리를 해제하는 것입니다.

-- 정정된 부분 --
그리고 ReleaseByteArrayElements() 메소드는 
native 코드에서 더이상 JVM의 element를 접근할 필요가 없을때 사용하는 것입니다.
void Release<PrimitiveType>ArrayElements(JNIEnv *env,
ArrayType array, NativeType *elems, jint mode); 
mode의 조건에 따라 달리 JVM에게 알리는 역할을 합니다. 
-- 끝 --

자세한 부분은 ReleaseByteArrayElements의 도움말을참조하시기 바랍니다.
또한 C의 메모리 할당 부분을 참조하시기 바랍니다.

-- 덧붙이는 글 --
참고로 C에서의 메모리 해제부분은 그 메모리를 다 쓰고 난 후에 해제하는 것이 바람직하므로
이부분은 전체로직을 보면서 해제가 제대로 되는지를 조사해야 합니다.

아래 사이트[인텍스 Q 7.5a]도 참조하시면 도움이 될것 같습니다.
http://www.cinsk.org/cfaqs/html/node9.html
  
제목 : Re: free부분을 강제로 넣었습니다.
글쓴이: 정완호(guest) 2005/05/17 13:44:35 조회수:637 줄수:24
고맙습니다 모사이트에 VC++로 개발을 해준것인데 
memory leak 문제가 발생하는 군요  
machine마다 정확히 동작하지 않는 JVM의 문제일까도 생각해 보았는데 
free를 명확하게 해주는 것이 좋은거 같습니다. 
리턴은 버퍼를 리턴해 주고요  그래서 아래와 같이 수정했습니다. 
잘돼야 할텐데 ... 내부적으로 어떻게 돌아가는지 모르니 ... 

char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes )
{    char nativeBuf[10000];
    size_t len = (*env)->GetArrayLength(env, javaBytes);
    jbyte *nativeBytes = (*env)->GetByteArrayElements(env, javaBytes, 0);
    char *nativeStr = malloc(len+1);   

    memcpy( nativeStr, nativeBytes, len );
    nativeStr[len] = '\0';
    (*env)->ReleaseByteArrayElements(
        env, javaBytes, nativeBytes, JNI_ABORT);

    memset( nativeBuf, 0x00, sizeof( nativeBuf ) );
    strcpy( nativeBuf, navtiveStr );
    free( nativfStr );   
    return nativeBuf;
}
제목 : Re: 위 처음 작성한 코드랑 동일한 코드입니다.
글쓴이: 사랑전쟁(lovewar) 2005/05/17 16:44:51 조회수:614 줄수:31

미안합니다. 지역변수에 대한 고려를 미쳐 못했습니다. C에서 함수가 끝나면, 함수 안에서 만들어진 automatic, local 변수는 없어집니다. 따라서 위 경우는 올바른 코드가 아닙니다 http://www.cinsk.org/cfaqs/html/node9.html 의 [Q 7.5a 구문] 다음 코드에서는 메모리를 얻는것에 실패하는 경우에 대한 대처법이 필요합니다. char *jbyteArray2cstr( JNIEnv *env, jbyteArray javaBytes ) { size_t len = (*env)->GetArrayLength(env, javaBytes); jbyte *nativeBytes = (*env)->GetByteArrayElements(env, javaBytes, 0) // Fail난 경우 대처법 char *nativeStr = malloc(len+1); // Fail난 경우 대처법 memcpy( nativeStr, nativeBytes, len ); nativeStr[len] = '\0'; (*env)->ReleaseByteArrayElements( env, javaBytes, nativeBytes, JNI_ABORT); return nativeStr; } memory leak에 대한 해결책 : 함수 jbyteArray2cstr() 를 사용하는 함수를 추적하여 메모리를 해제시키는지를 검사하는 방법과 // 추천 단일 프로세스로 운영된다면 지역변수(char nativeStr[10000])를 전역변수로 사용하는 방법이 고려될 수 있을겁니다. // 비추천

제목 : Re: 고맙습니다.
글쓴이: 정완호(guest) 2005/05/18 21:23:36 조회수:528 줄수:8
고맙습니다.
말씀해 주신 아래 방법을 써야 할거 같습니다.
"함수 jbyteArray2cstr() 를 사용하는 함수를 추적하여 
 메모리를 해제시키는지를 검사하는 방법"
호출하고 나서 리턴된 포인터를 free시켜 줘야 할거 같습니다. 
malloc( )함수가 메모리 할당되지 않았을때를 위한 코딩도 들어가야 할거 같구요 ^^;

 

[출처] http://www.javaservice.com/~java/bbs/read.cgi?m=&b=qna2&c=r_p&n=1116289917&p=15&s=t

Comments