[java] JNA 대신 JNI를 사용하여 네이티브 코드를 호출 하시겠습니까?

JNA는 JNI에 비해 네이티브 코드를 호출하는 데 사용하기가 약간 더 쉽습니다. 어떤 경우에 JNA를 통해 JNI를 사용 하시겠습니까?



답변

  1. JNA는 C ++ 클래스 매핑을 지원하지 않으므로 C ++ 라이브러리를 사용하는 경우 jni 래퍼가 필요합니다.
  2. 많은 메모리 복사가 필요한 경우. 예를 들어, 큰 바이트 버퍼를 반환하는 하나의 메서드를 호출하고 그 안의 내용을 변경 한 다음이 바이트 버퍼를 사용하는 다른 메서드를 호출해야합니다. 이 버퍼를 c에서 java로 복사 한 다음 다시 java에서 c로 복사해야합니다. 이 경우 복사없이 c에서이 버퍼를 유지하고 수정할 수 있기 때문에 jni가 성능면에서 승리합니다.

이것이 내가 만난 문제입니다. 아마도 더있을 것입니다. 그러나 일반적으로 jna와 jni의 성능은 크게 다르지 않으므로 JNA를 사용할 수있는 곳이면 어디에서나 사용하십시오.

편집하다

이 답변은 꽤 인기있는 것 같습니다. 다음은 몇 가지 추가 사항입니다.

  1. C ++ 또는 COM을 매핑해야하는 경우 JNAerator를 만든 Oliver Chafic의 라이브러리 인 BridJ가 있습니다. 아직은 젊은 도서관이지만 흥미로운 기능이 많이 있습니다.
    • 동적 C / C ++ / COM interop : C ++ 메서드 호출, C ++ 개체 생성 (및 Java에서 C ++ 클래스 하위 클래스!)
    • 제네릭을 잘 사용하는 간단한 유형 매핑 (포인터에 대한 훨씬 더 좋은 모델 포함)
    • 완전한 JNAerator 지원
    • Windows, Linux, MacOS X, Solaris, Android에서 작동
  2. 메모리 복사에 관해서는 JNA가 직접 ByteBuffer를 지원하므로 메모리 복사를 피할 수 있습니다.

따라서 가능한 한 JNA 또는 BridJ를 사용하고 성능이 중요한 경우 jni로 되 돌리는 것이 더 낫다고 생각합니다. 기본 함수를 자주 호출해야하는 경우 성능 저하가 눈에 띄기 때문입니다.


답변

이러한 일반적인 질문에 답하기는 어렵습니다. 가장 분명한 차이점은 JNI를 사용하면 유형 변환이 Java / 네이티브 경계의 기본 측면에서 구현되는 반면 JNA에서는 유형 변환이 Java로 구현된다는 것입니다. 이미 C 프로그래밍에 익숙하고 네이티브 코드를 직접 구현해야한다면 JNI가 너무 복잡해 보이지 않을 것이라고 생각합니다. Java 프로그래머이고 타사 네이티브 라이브러리 만 호출해야하는 경우 JNA를 사용하는 것이 JNI와 관련하여 명확하지 않은 문제를 방지하는 가장 쉬운 방법 일 것입니다.

차이점을 벤치마킹 한 적이 없지만 디자인 때문에 적어도 일부 상황에서 JNA를 사용한 유형 변환이 JNI보다 성능이 나쁘다고 가정합니다. 예를 들어 배열을 전달할 때 JNA는 각 함수 호출의 시작과 함수 호출의 끝에서이를 Java에서 원시로 변환합니다. JNI를 사용하면 어레이의 기본 “뷰”가 생성 될 때 자신을 제어 할 수 있으며 잠재적으로 어레이의 일부 뷰만 생성하고 여러 함수 호출에서 뷰를 유지하며 마지막에 뷰를 해제하고 원하는지 결정할 수 있습니다. 변경 사항을 유지하거나 (잠재적으로 데이터를 다시 복사해야 함) 변경 사항을 삭제합니다 (복사 할 필요 없음). Memory 클래스를 사용하여 JNA로 함수 호출간에 네이티브 배열을 사용할 수 있다는 것을 알고 있지만 메모리 복사도 필요합니다. JNI에서는 불필요 할 수 있습니다. 차이는 관련이 없을 수 있지만 원래 목표가 네이티브 코드로 애플리케이션의 일부를 구현하여 애플리케이션 성능을 높이는 것이라면 성능이 떨어지는 브리지 기술을 사용하는 것이 가장 확실한 선택이 아닌 것 같습니다.


답변

  1. JNA가 있기 몇 년 전에 코드를 작성하고 있거나 1.4 이전 JRE를 목표로하고 있습니다.
  2. 작업중인 코드가 DLL \ SO에 없습니다.
  3. LGPL과 호환되지 않는 코드를 작업 중입니다.

그것은 내가 두 가지를 많이 사용하지는 않지만 머릿속에서 떠 올릴 수있는 유일한 것입니다. 또한 그들이 제공하는 것보다 더 나은 인터페이스를 원한다면 JNA를 피할 수있는 것처럼 보이지만 Java로 코딩 할 수 있습니다.


답변

그건 그렇고, 우리 프로젝트 중 하나에서 우리는 매우 작은 JNI 발자국을 유지했습니다. 우리는 도메인 객체를 표현하기 위해 프로토콜 버퍼를 사용했기 때문에 Java와 C를 연결하는 네이티브 함수가 하나뿐이었습니다 (물론 C 함수가 다른 함수를 호출합니다).


답변

직접적인 대답은 아니고 JNA에 대한 경험이 없지만 JNA를 사용 하는 프로젝트 에서 SVNKit, IntelliJ IDEA, NetBeans IDE 등과 같은 이름을 보면 꽤 괜찮은 라이브러리라고 생각하는 경향이 있습니다.

실제로 JNI (지루한 개발 프로세스가있는)보다 간단 해 보이기 때문에 JNI 대신 JNA를 사용했을 것이라고 생각합니다. 안타깝게도 JNA는 현재 출시되지 않았습니다.


답변

JNI 성능을 원하지만 복잡성으로 인해 어려움을 겪는 경우 JNI 바인딩을 자동으로 생성하는 도구 사용을 고려할 수 있습니다. 예를 들어, JANET (면책 조항 : 내가 작성)을 사용하면 단일 소스 파일에 Java 및 C ++ 코드를 혼합 할 수 있습니다. 예를 들어 표준 Java 구문을 사용하여 C ++에서 Java로 호출 할 수 있습니다. 예를 들어 다음은 Java 표준 출력에 C 문자열을 인쇄하는 방법입니다.

native "C++" void printHello() {
    const char* helloWorld = "Hello, World!";
    `System.out.println(#$(helloWorld));`
}

그런 다음 JANET은 백틱이 포함 된 Java를 적절한 JNI 호출로 변환합니다.


답변

실제로 JNI와 JNA로 몇 가지 간단한 벤치 마크를 수행했습니다.

다른 사람들이 이미 지적했듯이 JNA는 편의를위한 것입니다. JNA를 사용할 때 네이티브 코드를 컴파일하거나 작성할 필요가 없습니다. JNA의 기본 라이브러리 로더는 내가 본 것 중 가장 사용하기 쉽고 사용하기 쉬운 것 중 하나입니다. 슬프게도 JNI에는 사용할 수없는 것 같습니다. (그래서 JNA의 경로 규칙을 사용하고 클래스 경로 (예 : jar)에서 원활한로드를 지원하는 System.loadLibrary ()에 대한 대안을 작성 했습니다 .)

그러나 JNA의 성능은 JNI의 성능보다 훨씬 떨어질 수 있습니다. 간단한 네이티브 정수 증가 함수 “return arg + 1;”을 호출하는 매우 간단한 테스트를 만들었습니다. jmh로 수행 한 벤치 마크에 따르면 해당 함수에 대한 JNI 호출이 JNA보다 15 배 빠릅니다.

네이티브 함수가 4 개 값의 정수 배열을 합산하는보다 “복잡한”예에서는 여전히 JNI 성능이 JNA보다 3 배 빠릅니다. 감소 된 이점은 아마도 JNI에서 배열에 액세스하는 방법 때문일 것입니다. 제 예에서는 일부 항목을 만들고 각 합산 작업 중에 다시 릴리스했습니다.

코드 및 테스트 결과는 github에서 찾을 수 있습니다 .