open:jni

JNI

Java Native Interface

  • Java class → JNI → C/C++ library : java 에서 native function 을 호출하는 경우
  • C/C++ library → JNI → Java class : C/C++ Program에서 Java의 함수를 이용하는 경우

JNI는 기존에 C/C++로 작성된 프로그램이나 시스템과의 연계를 위해 사용됩니다. JNI는 Java에서 Native code를 사용할 수 있는 인터페이스를 말하며, 좀 더 쉽게 말하면 C/C++로 작성한 API를 Java에서 호출하게 해주는 기능을 제공합니다.

JNI는 그 자체가 중요한 솔루션이 될 수는 없지만, 기존의 코드나 기존의 시스템 혹은 이질적인 다른 시스템과의 인터페이스에 사용될 수 있는 Java가 가진 좋은 기능 중의 하나입니다.

JNI는 Java와 Java 이외의 언어로 만들어진 애플리케이션이나 라이브러리가 상호 작용할 수 있도록 연결시켜 주는 인터페이스입니다.

java program 은 결국 JVM에서 실행된다. 이 JVM이 byte code를 실행하다가 native 함수를 보면 JNI를 통해 맞는 native 함수를 호출하게 된다. 여기서 JNI는 JVM의 일부이기 때문에 얘기하는 JNI는 JVM의 뜻도 같이 가지고 있다고 생각하자.

Java program 에서

System.loadLibrary("foo");

로 C/C++ library 를 load 하게 된다. JVM은 이 때 이 load된 library 의 “함수 심볼” 들을 뒤져서

JNI_OnLoad()

를 찾아서 함수를 호출한다. 이게 없으면, java program에서 호출한 native 함수와 mapping 되는 함수 이름을 찾아 놓는다.

이 때 C/C++ library 의 함수가 순수하게 C/C++로만 짜여져 있다면 JNI은 크게 할 일이 없다. 그냥 C/C++ 함수가 끝나서 return 해주면 그 때 다시 Java program으로 돌아가서 계속 프로그램을 수행하면 된다.

그런데 이 C/C++ 함수가 Java program의 class를 이용해야 한다면 얘기는 달라진다. 이 때부터 C/C++가 Java를 이용하기 위해 JNI가 가지고 있는 기능(함수)를 사용해야 한다.

이것을 위해 native 함수(C/C++ 함수)에서는 JNIEnv env*가 parameter로 넘어온다. 이 env를 가지고 JNI가 가지고 있는 기능(함수) 들을 사용할 수 있는 것이다.

이 함수들이 하는 일은 크게 2가지로 나눌 수 있다. 하나는 C/C++ library 안의 함수에서 원하는 변수(field)나 함수(method)를 찾아서 가져다 주는 것이고, 다른 하나는 C/C++ library 안의 함수가 Java의 변수에 값을 변경하거나(set), 함수를 호출(call) 할 수 있도록 해주는 것이다.

  1. get field / method
  2. set field / call method

근데 여기서 get field / method 를 할 때 JNI 가 알맞는 field 와 method를 찾을 수 있도록 정보를 줘야 한다. 이런 정보들은 아래와 같은 것들이 있다.

  • id
  • signature
  • class name

그래서 이 정보들은 JNI 함수를 호출할 때 parameter 로 넘겨주게 되어 있다.

이런 식으로 사용된 변수나 함수들은 전부 JNI를 통해 만들어서 reference를 native 함수 (C/C++ library 함수)로 전달되어진다. 이렇게 JNI에서 전달되는 reference는 global과 local, 2종류로 되어 있다. 그리고 대부분의 native 함수로 전달되는 reference는 local reference 이다.

그래서 C/C++ library에 static 변수를 둬서 Java instance 의 reference를 저장해 놨을 때 주의해야 한다. 그냥 일번저긍로 만든 instance 들은 JNI가 함수가 끝나는 시점에 사용하지 않는 녀석으로 되어버린다. (실제로 memory 를 free하는 것은 JVM에서 알아서 하는 것이기 때문에 내용이 남아 있을 수는 있지만 사용할 수는 없다. ) 그러므로 계속 사용하는 녀석으로 남아있기 위서는 NewGlobalRef() / DeleteGlobarRef() 를 사용해야 한다.

이렇게 만들어진 Reference는 DeleteGlobalRef()를 통해 명시적으로 삭제하겠다고 얘기하지 않는 이상 JVM이 지우지 않는다. 그러므로 C/C++ library에서 Java instance를 static 변수에 저장해서 이용하려면 NewGlobalRef()를 이용하도록 하자.

대부분에 local reference 들은 return 하면서 GC(garbage collector)가 지울 수 있는 상태가 된다. 하지만 2가지 경웨 명시적으로 local reference를 지우라고 한다.

  1. local reference가 참조하는 object가 memory를 많이 먹는 큰 object인 경우, 이 경우에는 native 함수가 local reference 를 지우지 않고 있어서 garbage collector 가 그 object를 못 지우는 경우가 생길 수 있기 때문에 이런 녀석은 제때에 지우라고 한다.
  2. local reference 를 너무 많이 사용하는 경우, local reference 를 추적하는 데에도 VM이 일정량의 memory를 사용해야 한다고 한다. 그렇기 때문에 너무 많은 local reference를 사용하면 메모리를 다 써버릴 수도 있다.
  • open/jni.txt
  • 마지막으로 수정됨: 2020/06/02 09:25
  • 저자 127.0.0.1