본문 바로가기

java

[Java] JNI(Java Native Interface)란?

JNI란?

JNI는 native code(C, C++, assembly 등)의 상호 운용을 위해서 만들어진 인터페이스다. JNI를 이용하면 JVM 내에서 실행되는 Java 코드로 native code 기반 애플리케이션이나 라이브러리를 상호 호출하여 사용할 수 있다. 

JNI의 장점은 native code로 작성된 코드를 활용하고자 할 때, 기존 Java로 제한된 코드의 구현에 영향을 미치지 않는다는 것이다. 이미 작성된 native code가 있다면, JNI를 이용하여 JVM 내에서 해당 코드가 정상적으로 작동하는 것을 보장하는 것이다. 

 

JNI 장단점

장점

- 하드웨어에 대한 동작을 native code로 제어할 수 있다

- 이미 native code를 사용해 구현한 라이브러리가 있을 때 Java에서 사용 가능하다

- assembly와 같은 저수준 언어로 시간이 매우 중요한(time-critical) 기능을 구현할 수 있다.

단점

- JVM의 장점인 WORA(Write once Run Anyware)가 적용되지 않는다. 다양한 플랫폼(Linux, Windows 등)의 형식에 맞게 새롭게 build 해주어야 한다.

- JNI를 통해 native code가 추가되면 프로그램의 복잡도가 높아진다.

- 데이터에 대한 타이블 맞춰줘야 할 수도 있다.

 

JNI를 활용한 native method는 어떻게 동작하는가?

JNI는 마치 추상메서드처럼, 'native' 키워드를 활용해 그 구현을 native code library에 위임한다. 우선 Java code를 작성해서 타겟이 되는 native code library를 호출하는 클래스와 메서드가 있다고 가정하자. 그럼 java code를 실행하기 위한 compile 전후에 java와 native code가 어떤 메서드와 data type을 호환하는지 communication 할 수 있는 중간 다리 역할이 필요한데, JDK가 포함하고 있는 'javah' 툴로 JNI header file을 생성해 제공한다. 이 정보를 가지고 native code compiler(GCC, Clang 등)가 native code를 컴파일하여 실행하고 그 결과를 java code 쪽에 다시 반환할 것이다.

Java 내장 모듈에서 지원하는 FileInputStream이 파일시스템의 파일에 접근할 때 native 메서드를 호출하는 과정을 살펴보면 다음과 같다. root 경로에 'myFile.txt' 파일을 생성하고 파일을 open 하여 해당 파일에 작성한 'hello'를 읽어 출력하는 코드다.

public class App {

    public static void main(String[] args) throws IOException {

        try (FileInputStream fis = new FileInputStream("myFile.txt");
            BufferedReader br = new BufferedReader(new InputStreamReader(fis));
        ) {
            String result = br.readLine();
            System.out.println(result);
        }
    }
}

 

FileInputStream의 파라미터로 파일명을 넘기고 해당 파일을 읽는 코드를 debug 하면 다음과 같이 FileInputStream의 생성자에서 'open0' native method를 호출한다.

public class FileInputStream extends InputStream {

	public FileInputStream(File file) throws FileNotFoundException {
        //생략
        
        open(name);
        FileCleanable.register(fd);       // open set the fd, register the cleanup
    }
    
    private void open(String name) throws FileNotFoundException {
        open0(name);
    }
    
    private native void open0(String name) throws FileNotFoundException;
}

 

해당 native method의 구현체는 OS에 따라 다를 수 있으며, OpenJDK17 github 소스에서는 다음과 같이 확인할 수 있다. https://github.com/openjdk/jdk17/blob/master/src/java.base/share/native/libjava/FileInputStream.c

JNIEXPORT void JNICALL
Java_java_io_FileInputStream_open0(JNIEnv *env, jobject this, jstring path) {
    fileOpen(env, this, path, fis_fd, O_RDONLY);
}

 

 

[참고자료]

https://docs.oracle.com/en/java/javase/17/docs/specs/jni/intro.html

https://www.baeldung.com/jni

 

 

'java' 카테고리의 다른 글

[Java] Dynamic Proxy란?  (0) 2023.03.21
[Java] Proxy란?  (0) 2023.03.20
[Java] Thread Dump  (0) 2023.03.01
[Java] 테스팅 툴 - JMeter  (1) 2023.02.21
[Java] 모니터링 툴 - VisualVM  (0) 2023.02.19