관리 메뉴

드럼치는 프로그래머

[JNI/NDK] JNI 동작원리 개념 - 1 본문

★─Programing/☆─JNI | NDK

[JNI/NDK] JNI 동작원리 개념 - 1

드럼치는한동이 2016. 7. 19. 09:30
안드로이드때문에 JNI 를 다시 보게 되었다. ^^ 여하튼 그래서 책을 보면서 이해한 내용을 그림으로 정리했다. 코드는 나중에 정리하기로 하고, 여기서는 대략적인 개념만 익히도록 하자. 사실 이 곳의 내용은 그저 내 생각을 정리한 것이라 정확하지 않은 면이 있다.(죄송 ㅜ.ㅜ) JNI에 대한 좀 더 정확하고 상세한 내용은 ref. 3 을 참조하도록 하자.

아래 그림은 JNI 를 사용하는 방법은 시작 프로그램에 따라 2가지가 있다.

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

이 중에서, 아래 글은 Java 에서 native function 을 호출하는 경우에 대한 이야기이다.

Java -> C/C++

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 되는 함수이름을 찾아 놓는다.[ref. 1]


순수한 c/c++ 로 된 함수

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


 

 


 

Java 의 함수를 이용해야 하는 c/c++

그런데 이 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 fiedl /method 를 할 때 JNI 가 알맞는 field 와 method 를 찾을 수 있도록 정보를 줘야 한다. 이런 정보들은 아래와 같은 것들이 있다
  • id
  • signature
  • class name
그래서 이 정보들은 JNI 함수를 호출할 때 parameter 로 넘겨주게 되어있다.

NewGlobalRef()

이런 식으로 사용된 변수나 함수들은 전부 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() / DeleteGlobalRef() 를 사용해야 한다.

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


Local reference 를 명시적으로 지워야 하는 상황[ref.3]

대부분에 local reference 들은 return 하면서 GC(garbage collector) 가 지울 수 있는 상태가 된다. 하지만 ref. 3 에서 2가지 경우에 명시적으로 local reference 를 지우라고 한다.
  1. local reference 가 참조하는 object 가 memory를 많이 먹는 큰 object 인 경우, 이 경우에는 native 함수가 local reference 를 지우지 않고 있어서 garbabe collector 가 그 object 를 못 지우는 경우가 생길 수 있기 때문에 이런 녀석은 제때에 지우라고 한다.
  2. local reference 를 너무 많이 사용하는 경우, local reference 를 추적하는 데에도 VM 이 일정량의 memory 를 사용해야 한다고 한다. 그렇기 때문에 너무 많은 local reference 를 사용하면 메모리를 다 써버릴 수도 있다.

Reference

  1. 인사이드 안드로이드
  2. http://i5on9i.egloos.com/4840655
  3. http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html

 

[출처] http://i5on9i.blogspot.kr/2013/01/jni.html

Comments