안녕하세요 돼지왕 왕돼지입니다.
이 글은 Oracle 에서 제공하는 Tutorial 문서를 번역한 것입니다.
출처 : http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/invocation.html#wp9502
오늘은 JNI Invocation API에 대해 한번 알아볼까요?
The Invocation API
Invocation API 는 software vendor 가 Java VM 을 native application 에 올릴 수 있게 해줍니다.Vendor 는 Java VM 소스 코드와의 링크를 하지 않고도 Java-enabled 앱을 출시 할 수 있습니다.
이번 장은 Invocation API 에 대한 overview 로 시작합니다. 그 다음은 Invocation API function 의 reference page 입니다.
Overview
다음 코드 예제는 어떻게 Invocation API 를 사용하는지를 보여줍니다. 이 예제에서 C++ code 는 Java VM 을 만들고 static method 를 호출합니다. 함수 이름은 Min.test 입니다. 깔끔히 보기 위해 error checking 은 생략했습니다.
#include <jni.h> /* where everything is defined */
...
JavaVM *jvm; /* denotes a Java VM */
JNIEnv *env; /* pointer to native method interface */
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=/usr/lib/java";
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface pointer in env */
JNI_CreateJavaVM( &jvm, &env, &vm_args );
delete options;
/* invoke the Main.test method using the JNI */
jclass cls = env->FindClass( "Main" );
jmethodID mid = env->GetStaticMethodID( cls, "test", "(I)V" );
env->CallStaticVoidMethod( cls, mid, 100 );
/* We are done. */
jvm->DestroyJavaVM();
이 예제는 API의 3가지 함수를 사용합니다. Invocation API 는 native application 이 JNI interface pointer 를 사용하여 VM freature 를 사용할 수 있도록 합니다. 디자인은 Netscape의 JRI Embedding Interface 와 비슷합니다.
Creating the VM
JNI_CreateJavaVM() 함수는 Java VM 을 load 하고 초기화합니다. 그리고 JNI interface pointer 에 pointer를 return 합니다. JNI_CreateJavaVM() 을 호출한 thread 는 main thread 로 간주됩니다.
Attaching to the VM
JNI interface pointer (JNIEnv) 는 main thread 에서만 유효합니다. 다른 thread 에서 Java VM 을 접속하려면 반드시 AttachCurrentThread() 를 불러 VM 에 자신을 먼저 붙이고, JNI interface pointer 를 얻어야 합니다. 한번 VM에 붙으면, native thread 는 native 함수에서 보통의 Java thread 처럼 작동합니다. native thread 는 DetachCurrentThread() 를 호출해서 떼어내기 전까지는 계속 VM에 붙은채로 있습니다.
붙어있는 thread 는 적당한 양의 일을 하려면 충분한 stack 공간을 가지고 있어야 합니다. thread 마다 할당하는 stack 공간은 OS 마다 다릅니다. 예를 들어 pthreads 를 이용하면 stack size 는 pthread_attr_t argument 를 pthread_create 에 전달함으로서 결정할 수 있습니다.
Detaching form the VM
VM 에 붙은 native thread는 "반드시" DetachCurrentThread() 를 불러주어 thread가 종료하기 전에 VM 에서 떼 주어야 합니다. thread 는 call stack 에 Java 함수가 있는 한 스스로 떨어지지 않습니다.
Unloading the VM
JNI_DestroyJavaVM() 함수는 Java VM 을 unload 합니다. JDK/JRE 1.1 의 경우는 오직 main thread 만 VM 을 unload 할 수 있습니다. DestroyJavaVM 을 호출함으로서 말이죠. JDK/JRE 1.2 의 경우는 그 제약사항이 없어졌습니다. 어떤 thread 든지 DestoryJavaVM 을 불러 VM 을 unload 할 수 있습니다.
VM 은 현재 thread 가 유일한 non-daemon user thread 일 경우가 될 때까지 기다렸다가 unload 됩니다. User threads 는 Java thread 와 VM 에 붙은 native thread 모두를 이릅니다. 이 제약사항이 있는 이유는 user thread 가 system resource 를 가지고 있을 수 있기 때문입니다. 예를 들면 lock, window 등 말이죠. VM 은 자동으로 그런 resource 들을 free 하지 못합니다. VM 이 unload 할 때 현재 thread 만이 유일한 thread 임을 제약함으로서 thread 들이 가지고 있는 system resource 를 release 하는 것은 프로그래머의 책임이 되었습니다.
Library and Version Management.
JDK/JRE 1.1 의 경우 한번 native library 가 로드되면, 이것은 모든 class loader 에게 보여집니다. 그래서 다른 class loader에 있는 2개의 class는 같은 native method 에 연결될 수 있습니다. 이것은 2가지 문제를 초래합니다.
- 한 class 가 잘못된 native library 와 연결될 수 있습니다. 이건 같은 이름을 가진 다른 class loader 에 의해 불려진 library 일 수 있습니다.
- Native 함수들은 다른 class loader 로 불려진 class 들과 쉽게 섞일 수 있습니다. 이것은 class loader 가 제공하는 name space 구분사항을 어기는 것이며, type safety 문제를 야기합니다.
JDK/JRE 1.2의 경우 매 class loader 가 각자의 native library set 을 관리합니다. 같은 JNI native library 는 한 class loader 에서 두번 이상은 불리지 못합니다. 두번 부르는 것은 UnsatisfiedLinkError 를 야기합니다. 예를 들면 2개의 class loader가 native library 를 load하려 한다면, System.loadLibrary 는 UnsatisfiedLinkError 를 던집니다. 이 새로운 접근법은 다음과 같은 장점이 있습니다.
- class loader 가 제공하는 name space separation 이 native libary 에 적용됩니다. native library 는 다른 class loader 와 섞이지 않습니다.
- 게다가, native library 는 load 한 class loader 가 GC 되면 자동적으로 함께 unload 됩니다.
Version control 이나 resource management 를 사용하기 위해서 JDK/JRE 1.2 버전의 JNI library 는 추가적으로 2개의 function ( JNI_OnLoad, JNI_ONUnload ) 을 지원합니다. ( 자세한 API 문서는 사이트를 참조하세요 )
Invocation API Functions
JavaVM type 은 Invocation API function table 의 pointer 입니다. 다음의 코드는 function table 의 예를 보여줍니다.
typedef const struct JNIInvokeInterface *JavaVM;
const struct JNIInvokeInterface ... = {
NULL,
NULL,
NULL,
DestroyJavaVM,
AttachCurrentThread,
DetachCurrentThread,
GetEnv,
AttachCurrentThreadAsDaemon
};
JNI_GetDefaultJavaVMInitArgs(), JNI_GetCreatedJavaVMs(), JNI_CreateJavaVM() 3개의 Invocation API 함수는 JavaVM function table 의 일부가 아니라는 점을 주목하세요. 이 함수들은 JavaVM Structure 를 이용하지 않아도 사용할 수 있습니다.
자세한 API 는 사이트를 참조하세요.
'프로그래밍 놀이터 > 안드로이드, Java' 카테고리의 다른 글
[Android/안드로이드] JNI Tutorial HelloJNI ( 샘플 소스 포함 ) (2) | 2012.03.24 |
---|---|
[Java] JNI Tutorial ( HelloJNI ) (4) | 2012.03.24 |
[Java] JNI functions. (0) | 2012.03.22 |
[Java] JNI Type 과 Data Structure. (0) | 2012.03.22 |
[Java] Thread 의 Monitor 에 대한 개념. (0) | 2012.03.22 |
댓글