답변:
이것이 내가 만난 문제입니다. 아마도 더있을 것입니다. 그러나 일반적으로 jna와 jni의 성능은 크게 다르지 않으므로 JNA를 사용할 수있는 곳이면 어디에서나 사용하십시오.
편집하다
이 답변은 꽤 인기있는 것 같습니다. 다음은 몇 가지 추가 사항입니다.
따라서 가능한 한 JNA 또는 BridJ를 사용하고 성능이 중요한 경우 jni로 되 돌리는 것이 더 낫다고 생각합니다. 기본 함수를 자주 호출해야하는 경우 성능 저하가 눈에 띄기 때문입니다.
JNIEXPORT
함수 만 호출 할 수 있습니다 . 현재 JNI를 사용하는 JavaCpp를 옵션으로 탐색하고 있지만 바닐라 JNI가이를 지원한다고 생각하지 않습니다. 내가 간과하고있는 바닐라 JNI를 사용하여 C ++ 멤버 함수를 호출하는 방법이 있습니까?
이러한 일반적인 질문에 답하기는 어렵습니다. 가장 분명한 차이점은 JNI를 사용하면 유형 변환이 Java / 네이티브 경계의 기본 측면에서 구현되는 반면 JNA에서는 유형 변환이 Java로 구현된다는 것입니다. 이미 C 프로그래밍에 익숙하고 네이티브 코드를 직접 구현해야한다면 JNI가 너무 복잡해 보이지 않을 것이라고 생각합니다. Java 프로그래머이고 타사 네이티브 라이브러리 만 호출해야하는 경우 JNA를 사용하는 것이 JNI와 관련하여 명확하지 않은 문제를 방지하는 가장 쉬운 방법 일 것입니다.
차이점을 벤치마킹 한 적이 없지만 디자인 때문에 적어도 일부 상황에서 JNA를 사용한 유형 변환이 JNI보다 성능이 나쁘다고 가정합니다. 예를 들어 배열을 전달할 때 JNA는 각 함수 호출의 시작과 함수 호출의 끝에서이를 Java에서 원시로 변환합니다. JNI를 사용하면 어레이의 기본 "뷰"가 생성 될 때 자신을 제어 할 수 있으며 잠재적으로 어레이의 일부 뷰만 생성하고 여러 함수 호출에서 뷰를 유지하며 마지막에 뷰를 해제하고 원하는지 결정할 수 있습니다. 변경 사항을 유지하거나 (잠재적으로 데이터를 다시 복사해야 함) 변경 사항을 삭제합니다 (복사 할 필요 없음). Memory 클래스를 사용하여 JNA로 함수 호출간에 네이티브 배열을 사용할 수 있다는 것을 알고 있지만 메모리 복사도 필요합니다. JNI에서는 불필요 할 수 있습니다. 차이는 관련이 없을 수 있지만 원래 목표가 네이티브 코드로 애플리케이션의 일부를 구현하여 애플리케이션 성능을 높이는 것이라면 성능이 떨어지는 브리지 기술을 사용하는 것이 가장 확실한 선택이 아닌 것 같습니다.
그것은 내가 두 가지를 많이 사용하지는 않지만 머릿속에서 떠 올릴 수있는 유일한 것입니다. 또한 그들이 제공하는 것보다 더 나은 인터페이스를 원한다면 JNA를 피할 수있는 것처럼 보이지만 Java로 코딩 할 수 있습니다.
그건 그렇고, 우리 프로젝트 중 하나에서 우리는 매우 작은 JNI 발자국을 유지했습니다. 우리는 도메인 객체를 표현하기 위해 프로토콜 버퍼를 사용했기 때문에 Java와 C를 연결하는 네이티브 함수가 하나뿐이었습니다 (물론 C 함수가 다른 함수를 호출합니다).
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에서 찾을 수 있습니다 .
내가 뭔가를 놓치고 있지 않는 한 JNA와 JNI의 주요 차이점은 JNA를 사용하면 네이티브 (C) 코드에서 Java 코드를 호출 할 수 없다는 것입니까?
내 특정 응용 프로그램에서 JNI는 사용하기 훨씬 쉬웠습니다. 직렬 포트에서 연속 스트림을 읽고 쓸 필요가있었습니다. JNA에서 매우 관련된 인프라를 배우려고하는 것보다 6 개의 함수 만 내 보낸 특수 목적 DLL을 사용하여 Windows에서 기본 인터페이스를 프로토 타입하는 것이 훨씬 쉽다는 것을 알았습니다.