본문 바로가기

망각/JAVA/JNI

JNI 간단 메모

# c 스트링을 자바 스트링으로 변환

char [] test_str = "abc";

// C
jstring  java_string = (*env)->NewStringUTF(env, test_str);

//C++
jstring  java_string = env->NewStringUTF(test_str);


# 자바 스트링에서 c 스트링으로 변환

char buf[128]
const char * c_string = env->GetStringUTFChars(java_string, 0);

// strcpy(buf, c_string ...)
// ...

env->ReleaseStringUTFChars(java_string, c_string);


# C 배열 vs Java 배열

기본형 배열

// native 메서드 선언
private native int sumArray(int [] arr);


// native 메서드 구현
JNIEXPORT jint JNICALL Java_IntArray_sumArray(JNIEnv * env, jobject obj, jintArray arr) {
jint buf[10];
jint i, sum = 0;
env->GetIntArrayRegion(arr, 0, 10, buf);
for (i = 0; i < 10; ++i) {
sum += buf[i];
}
return sum;
}

구찮다..
객체 배열, 메서드(static 포함) id 등은 문서 참조..


# Local reference

JNI로 프로그래밍할 떄 자바 객체에 대한 참조들을 사용할때가 필요할 것이다.
기본적으로 JNI 가비지컬렉션에 걸리것에 확신하기 위해 지역 참조를 생성한다.
이것 때문에, 당신은 아래 샘플 코드처럼, 나중에 다시 사용하기 위해 지역 참조를 저장하려고 하는,
고의적이지않은 합법적이지 않은 코드를 작성할 것이다.

1. static jmethodID mid;
2.
3. JNIEXPORT jstring JNICALL Java_Sample1_accessMethod(JNIEnv * env, jobject obj) {
4. ...
5. cls = env->GetObjectClass(obj);
6. if (cls != 0)
7.  mid = env->GetStaticMethodID(cls, "addInt", "(I)I");
8. ...
9.}


이 코드는 7라인 때문에 유효하지 않다.
mid 는 methodID 이고 GetStaticMethodID()는 methodID를 리턴한다.
리턴된 methodID 는 지역 참조이므로 지역 참조를 전역 참조로서 할당 할 수 없다.
mid는 전역 참조이다.

Java_Sample1_accessMethod()가 리턴된 후에, mid 참조는 할당된 지역 참조가 범위를 벗어났으므로 더 이상 유효하지 않다.
mid 를 사용하려 하면 잘못된 결과나 JVM의 충돌이 일어날것이다.

#Creating a global reference

이 문제를 고치기 위해, 전역 참조를 생성하고 사용해야만 한다.
전역 참조는 명시적으로 그것을 해제하기(분명히 이것을 기억해야한다) 전까지 유효하게 유지된다.
메모리릭때문에 참조를 해제하는것에 실패할수 있다.

아래 코드는 NewGlobalRef()로 전역 참조를 생성하고 DeleteGlobalRef()로 그것을 지운다.

static jmethodID mid;

JNIEXPORT jstring JNICALL Java_Sample1_accessMethod(JNIEnv * env, jobject obj) {
cls = env->GetObjectClass(obj);
if (cls != 0) {
mid1 = env->GetStaticMethodID(cls, "addInt", "(I)I");
mid = env->NewGlobalRef(mid1);
...
}