소개
JNI( Java Native Interface) 는 프로그래밍 인터페이스 이다. JNI 는 JVM 내부에서 실행되는 Java 코드를
C, C++ 등과 같은 걸로 구성된 라이브러리 등을 내부적으로 운영할 수 있도록 한다.
JNI 의 사용유형은 다음처럼 두가지 경우이다.
- Java→ C/C++
- 가장일반적인 형태로 android 가 대표적
- OS 의 native 한 부분을 java 로 구현하기 어렵거나 성능적 이슈가 있는 경우 사용된다.
- 기존의 legacy 시스템
- 특수 하드웨어 제어
- C/C++ → Java
- Lucene 엔진이 대표적( 기존 Java 엔진의 유용성이 매우 큰 경우 )
- 기능, 성능면에서 이점은 없으나 기존 시스템이 Java 로 구현이 완전하게 되어 있는 경우
- 새로 구축하는 비용이 부담되는 경우 사용됨
JNI 를 통해 Java Interface 만 제공하는 MiddleWare 로의 접근에 대한 가능성 조사이며 JDBC 를 사용한다는 전제로
C/C++→ Java 경우에 대해서만 언급한다.
장점
- C/C++ 인터페이스를 제공하지 않는 경우에도 우회적으로 사용이 가능하다.
- 최신 트랜드에 따르는 Software 의 대부분은 Java 를 우선지원하거나 Java로 만들어져 있다.
단점
- JDBC 에 준하는 C/C++ 인터페이스를 설계해야 한다.
- ODBC 대비 throughput 및 latency 저하가 예상된다.
- 관리포인트 증가
- JVM 을 실행한 상태에서 JNI 를 이용한 메모리 관리
- GC( garbage collection ) 관리를 통한 성능 관리
- 기존 Java 사용하던 환경과 다른 관리 기준
example
JNI 를 이용한 간단한 테스트 example
Java Code
public class JniTest{
public static void main(String[] args){
System.out.println("Hello World " + args[0] );
}
}
C Code
#include <jni.h>
#define PATH_SEPARATOR ';'
#define USER_CLASSPATH "."
void main(){
JNIEnv *env;
JavaVM *jvm;
jint res;
jclass cls;
jmethodID mid;
jstring jstr;
jclass stringClass;
jobjectArray args;
JavaVMInitArgs vm_args;
JavaVMOption options[1];
options[0].optionString = "-Djava.class.path=" USER_CLASSPATH;
vm_args.version = 0x00010002;
vm_args.options = options;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = JNI_TRUE;
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
if (res < 0) {
fprintf(stderr, "Can't create Java VM\n");
exit(1);
}
cls= (*env)->FindClass(env, "JniTest");
if (cls == 0) {
fprintf(stderr, "Can't find JniTest class\n");
exit(1);
}
mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V");
jstr = (*env)->NewStringUTF(env, "arg1");
stringClass = (*env)->FindClass(env, "java/lang/String");
args = (*env)->NewObjectArray(env, 1, stringClass, jstr);
(*env)->CallStaticVoidMethod(env, cls, mid, args);
if((*env)->ExceptionOccurred(env)){
(*env)->ExceptionDescribe(env);
}
(*jvm)->DestroyJavaVM(jvm);
}
컴파일 및 실행
# jni.h 헤더파일을 위해
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.212.b04-0.el7_6.x86_64
# $JAVA_HOME/include
# $JAVA_HOME/include/linux 가 필요하다.
INC=-I$JAVA_HOME/include
INC2=-I$JAVA_HOME/include/linux
# JNI 라이브러리
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/jvm/jre-1.8.0-openjdk-1.8.0.212.b04-0.el7_6.x86_64/lib/amd64/server
LIB=/usr/lib/jvm/jre-1.8.0-openjdk-1.8.0.212.b04-0.el7_6.x86_64/lib/amd64/server/libjvm.so
gcc $INC $INC2 JniTest.c $LIB
$ a.out
Hello World arg1
chlee@dev:~/workspace/jni
$