JNI 사용법
//Test1.java
class Test1{
static
{
System .loadLibrary ("TestDll" ); // JVM 에 등록되어 있는 path 의 dll 을 불러오는 함수이다.
//System.load(¡°c://winnt//system32//TestDll.dll¡±);
}
public static void main (String ar [])
{
System .out .println ("Hello world from Java" );
Test1 t =new Test1 ();
t .inDll (); // JVM 은 loaded DLL 에서 inDll 을 찾을 것이다. System.loadLibrary()로 이미 load 해 놓았다.
}
public native void inDll ();
}
먼저 native method를 사용하는 java file을 만들자.
이제 void inDll (); 함수가 들어있는 .dll 파일 (native code) 을 만들어야 한다.
만들 때 TestDll.dll 안에
C:\> Javah -jni Test1로 .h 를 만들고, 이 것을 바탕으로 C/C++(native code)를 작성하고, 그것으로 library를 만들면 된다.
궁금증
VM 은 어떻게 native method를 접근할 수 있나?VM이 내부적으로 각 class loader에 대해서 loaded native libraries 의 lis t 가 있다. 대충 아래 그림의 느낌일 것이다.(불확실하다.^^;) 그러면 이 library 에 가서 알맞은 name 의 mthod를 호출 할 것이다.
그럼 반대로 JVM의 method를 native code 에서 어떻게 접근할까?
JVM 은 native method call 할 때 argument 로 JNI interface pointer를 넘기게 된다. 나중에 보겠지만, 이 pointer로 java 의 다른 collection class 들을 call 할 수 있게 된다.
그림 출처 : http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/design.html#wp9502 |
- Thread 1개 일 때 - VM 에서 생성하는 thread 1개 에 JNI interface pointer가 1개 가 있다. 그래서 같은 thread 에서 어떤 native method를 부른다고 해도 같은 JNI interface pointer가 argument 로 넘어갈 것이다.
- Thread 2개 이상 - 지만 thread가 2개가 있다면 같은 native method를 호출한다고 해도 다른 JNI interface pointer 가 argument 로 넘어갈 것이다.
Garbage collector 와 관련해서 …
native method 에서 object를 사용하게 되면, garbage collector가 그 object를 지워서는 안 된다. 그러므로 JVM 은 native method 로 가는 passed all object를 keep track 하게 된다. 그리고 native method에서 더 이상 쓰이지 않게 된다면, VM 에다 이 object를 더 이상 쓰지 않는다고 알려주게 된다.JNI 1.1 Specification
- http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/jniTOC.html
- http://pllab.kw.ac.kr/j2seapi/guide/jni/spec/jniTOC.html
모든 native methods 는 pre-linked with VM 이다.
System.loadLibrary() 을 호출하는 순간이 load library를 하는 순간이 되지 않고, pre-linked 되는 것이다.
때론 statically linked functions 가 필요할 지 모른다.
이 때는 RegisterNatives() 를 호출해서 class 과 연관되어서 native methods를 등록할 수 있다.
package pkg ;
class Cls {
native double f(int i, String s);
...
}
위의 native method 의 name이 Java_ pkg _Cls _f_ILjava_lang_String_2 로 바뀐다.
맨 뒤의 숫자 2 는 argument 개수를 얘기한다.
VM 의 dynamic linker 는 short name (name without argument signature) 를 먼저 검색한다. 만약 그것으로 결정이 되지 않는다면, long name 을 보게 되는 것이다.
왜 Java 에서 native method 를 정의하고, 이것의 header file을 생성(javah.exe) 하고 나서, 그 것을 가지고 native method 를 implement 를 하고, compile 해서 .dll 등의 library를 만들어야 하는 건가?
Java에서 지금 현재 존재하는 .dll 안에 있는 함수를 바로 쓸 수는 없는 것인가?
없을 듯 하다. 일단 JVM 에서 쓸 수 있는 loaded library 는 역시 Java code 상에서 System.loadLibrary() 등을 통해 명시되어야 한다. 그래야 JVM 에서 loaded library에 대해서 list를, 즉 정보를 가질 수 있다.
그럼 그냥 아무런 .dll 을 호출했다고 하자. 그렇다면, 그 안의 함수를 어떻게 호출할 것인가? 그 안의 함수가 있다고 하나 VM 에서 그 함수를 호출할 방법이 없다. 왜냐하면, g()라는 함수를 호출한다고 해도, VM 은 그것을 자신만의 방식으로 naming 하고 그 name의 native method를 호출하게 된다. 그러므로, 같은 이름이 없다면 불가능하다. 만약 naming 방식을 JVM 에서 바꾼다면 가능할지도 모르겠다.
package pkg;
class Cls {
native double f(int i, String s);
...
}
The C function with the long mangled name Java_pkg_Cls_f_ILjava_lang_String_2 implements native method f:
Code Example 2-1 Implementing a Native Method Using C
jdouble Java_pkg_Cls_f__ILjava_lang_String_2 (
JNIEnv *env , /* interface pointer */
jobject obj, /* "this" pointer */
jint i, /* argument #1 */
jstring s) /* argument #2 */
{
/* Obtain a C-copy of the Java string */
const char *str = (*env)->GetStringUTFChars(env, s, 0);
/* process the string */
...
/* Now we are done with str */
(*env)->ReleaseStringUTFChars(env, s, str);
return ...
}
Note that we always manipulate Java objects using the interface pointer env . Using C++, you can write a slightly cleaner version of the code, as shown in Code Example 2-2 :
Code Example 2-2 Implementing a Native Method Using C++
extern "C" /* specify the C calling convention */
jdouble Java_pkg_Cls_f__ILjava_lang_String_2 (
JNIEnv *env , /* interface pointer */
jobject obj, /* "this" pointer */
jint i, /* argument #1 */
jstring s) /* argument #2 */
{
const char *str = env->GetStringUTFChars(s, 0);
...
env->ReleaseStringUTFChars(s, str);
return ...
}
With C++, the extra level of indirection and the interface pointer argument disappear from the source code. However , the underlying mechanism is exactly the same as with C. In C++, JNI functions are defined as inline member functions that expand to their C counterparts.
댓글 없음:
댓글 쓰기