development

JNA 대신 JNI를 사용하여 기본 코드를 호출 하시겠습니까?

big-blog 2020. 7. 26. 11:39
반응형

JNA 대신 JNI를 사용하여 기본 코드를 호출 하시겠습니까?


JNA는 JNI와 비교하여 원시 코드를 호출하는 데 사용하기가 상당히 쉽습니다. 어떤 경우에 JNA를 통해 JNI를 사용 하시겠습니까?


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

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

편집하다

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

  1. 당신은 C ++ 또는 COM을지도해야하는 경우라고 올리버 Chafic, JNAerator의 창조자에 의해 도서관이 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과 호환되지 않는 코드를 작업 중입니다.

그것은 내가 무거운 사용자가 아니지만 내 머리 꼭대기에서 떠 올릴 수있는 것입니다. 또한 그들이 제공하는 인터페이스보다 더 나은 인터페이스를 원한다면 Java에서 JNA를 피할 수있는 것처럼 보입니다.


그건 그렇고, 우리 프로젝트 중 하나에서 매우 작은 JNI 풋 프린트를 유지했습니다. 우리는 도메인 객체를 표현하기 위해 프로토콜 버퍼를 사용 했으므로 Java와 C를 연결하기위한 단 하나의 고유 함수 만 가지고있었습니다 (물론 C 함수는 다른 함수를 호출 할 것입니다).


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

실제로 필자는 JNI (지루한 개발 프로세스가있는 JNI)보다 단순 해 보일 때 JNI 대신 JNA를 사용했을 것입니다. 너무 나쁘다 .JNA는 현재 공개되지 않았다.


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

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에서 찾을 수 있습니다 .


JNI와 JNA를 조사하여 성능 비교를 위해 프로젝트 중 dll을 호출하기 위해 그들 중 하나를 결정해야했기 때문에 실시간 제약이있었습니다. 결과는 JNI가 JNA보다 약 40 배 높은 성능을 보여 주었다. JNA의 성능 향상을위한 요령이있을 수 있지만 간단한 예에서는 속도가 매우 느립니다.


Unless I'm missing something, isn't the main difference between JNA vs JNI that with JNA you can't call Java code from native (C) code?


In my specific application, JNI proved far easier to use. I needed to read and write continuous streams to and from a serial port -- and nothing else. Rather than try to learn the very involved infrastructure in JNA, I found it much easier to prototype the native interface in Windows with a special-purpose DLL that exported just six functions:

  1. DllMain (required to interface with Windows)
  2. OnLoad (just does an OutputDebugString so I can know when Java code attaches)
  3. OnUnload (ditto)
  4. Open (opens the port, starts read and write threads)
  5. QueueMessage (queues data for output by the write thread)
  6. GetMessage (waits for and returns data received by the read thread since the last call)

참고URL : https://stackoverflow.com/questions/1556421/use-jni-instead-of-jna-to-call-native-code

반응형