[컴][자바] JNI 사용법


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를 호출 할 것이다.
blip000000

그럼 반대로 JVM의 method를 native code 에서 어떻게 접근할까? blip000001
JVM 은 native method call 할 때 argument 로 JNI interface pointer를 넘기게 된다. 나중에 보겠지만, 이 pointer로 java 의 다른 collection class 들을 call 할 수 있게 된다.
blip000002
그림 출처 : 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
OS가 dynamic linking 을 지원하지 않는다면,
모든 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.

댓글 없음:

댓글 쓰기