2014-09-12 1 views
1

Java에서 C++로 문자열 매개 변수를 전달하는 JNI 인터페이스를 설계하고 있습니다. 고성능이 필요하고 Direct ByteBuffer 및 String.getBytes()를 사용하여 상당히 잘 수행 할 수 있지만 문자열을 C/C++로 전달할 경우의 불이익은 여전히 ​​상당히 높습니다. 최근에는 Open JDK의 Unsafe 클래스에 대해 읽었습니다. This excellent page 나를 시작 시켰지만 Unsafe가 비참한 것으로 나타 났지만 이해하기 쉽도록 문서화되지 않았습니다.안전하지 않은 포인터 고정

Unsafe 클래스를 사용하여 문자열에 대한 포인터를 얻은 다음 C++에 전달하면 C++ 코드를 입력하기 전에 개체가 이동했을 위험이 있습니까? 그리고 C++이 실행되는 동안에도? 또는 안전하지 않은 코드에 의해 제공된 주소가 어떻게 고정되어 있습니까? 그들이 고정되어 있지 않다면 어떻게 이러한 안전하지 않은 포인터가 유용할까요?

+0

일부 코드를 게시하면 크게 도움이됩니다. 특히 C++ 코드가 Java 비트에서 동기식으로 호출되는지 여부 또는 다중 스레드가 있는지 여부를 확인하는 데 도움이됩니다. 또한, string에 대한 포인터는'char *'또는'std :: string *'을 의미합니까? 코드로 답을 많이 얻었습니다! – Luis

+0

페널티가 UTF-16에서 C++ 코드가 사용하는 인코딩으로 변환되는 것 같습니다. C++ 코드가 카운팅 된 (끝나지 않은) UTF-16을 처리 할 수 ​​있다면'GetStringChars'와'GetStringLength'에서 변환이나 복사가 필요합니다. "문자열에 대한 포인터"가 의미하는 바가 아닙니까? –

+0

Tom. 거기에 아무 것도하지 않더라도 Java-> JNI-> C++에서 객체 (문자열 포함)를 전달할 때 성능 저하가있는 것으로 보입니다. 그 비용은 오래 걸리는 비용보다 상당히 높습니다. 그 비용이 내재적 인 지역 참조를 만드는 데에만 기인하는지는 불확실합니다. 이유가 무엇이든 그 비용은 고통 스럽습니다. 또한 GetStringChars에는 측정 할 수있는 비용이 있습니다. 나는 그것이 바이트의 COPY에 대한 포인터를 받기 때문에 읽었다 고 생각한다. 또는 객체가 고정되어야한다. 어쨌든 당신은 지연을 일으키는 것을 상상할 수 있습니다. – user3624334

답변

1

안전하지 않은 것은 JNI와 상호 작용하지 않습니다. Unsafe를 통해 얻은 결과는 언제든지 바뀔 수 있습니다 (C++과 병행하더라도).

JNI API는 배열 내용에 액세스하기 위해 메모리에 객체를 고정 할 수 있습니다 (HotSpot JVM에서 GC를 차단하므로 GC 일시 중지 기간에 부정적인 영향을 미칠 수 있음).

특히 Get * ArrayElements는 명시 적으로 Release * ArrayElements를 수행 할 때까지 배열을 핀 배열합니다. GetStringChars는 비슷한 방식으로 작동합니다.

Direct ByteBuffer 힙 외부의 메모리 버퍼에 대한 포인터를 보유하고 있으며,이 버퍼가 움직이지 않고 네이티브 코드에 액세스 할 수 있습니다.

1

java.misc.Unsafe에 대한 Java source을 읽었으며 통찰력이 약간 있습니다.

안전하지 않은 메모리는 최소한 두 가지 방법으로 처리됩니다.

  1. allocateMemory/reallocateMemory/freeMemory에서/등 - 힙이 그래서 GC'ing의 도전에 직면하지 밖에서 지금까지 내가 메모리의 할당을 말할 수있다. 나는 이것을 간접적으로 테스트했으며 리턴 된 long은 메모리에 대한 포인터 일 뿐인 것처럼 보입니다. 이 유형의 메모리는 JNI를 통해 원시 코드로 전달하는 것이 안전합니다. 그리고 응용 프로그램 Java 코드는이 스타일의 메모리 포인터를 지원하는 다른 고유 한 Unsafe 메서드 중 일부를 사용하여 JNI 호출 전후에 신속하게 수정/쿼리 할 수 ​​있어야합니다.

  2. 개체 + 오프셋 -이 메서드는 개체에 대한 포인터와 개체에서 값을 가져 오거나 수정할 위치를 나타내는 "오프셋"토큰을 허용합니다. 객체는 항상 Java 힙에 있지만 아마도 객체를 이러한 메소드에 전달하면 GC 합병증을 해결하는 데 도움이 될 것입니다. "offset"은 실제 오프셋이 아닌 "쿠키"인 것처럼 들리지만 배열의 경우 arrayBaseOffset()은 산술적으로 조작 할 수있는 "오프셋"을 반환합니다. 이 객체 + 오프셋이 JNI 코드에 안전한지 여부는 알 수 없습니다. 나는 (위험하게) JNI를 통과 할 수있는 힙의 자바 객체에 직접 포인터를 생성하는 메소드를 보지 못했다. 하나는 객체와 오프셋을 전달할 수 있지만 JNI를 통해 객체를 전달하는 비용을 감안할 때이 방법은 어쨌든 매력적이지 않습니다.

처럼 (1), 내 게시물에 참조 된 페이지와 관련된 code 아마 JNI 상호 작용에 대한 매우 안전합니다. String을 처리 할 때 객체 + 오프셋 접근 방식을 취하지 만 직접 Java 힙 외부에있는 직접 ByteBuffer를 처리 할 때는 접근 방식 (1)을 사용합니다. 직접 ByteBuffer 's는 매우 JNI 친화적이며 종종 Tom에게 위의 내 의견에서 언급 한 JNI Object 전달 비용을 피하는 방식으로 사용될 수 있습니다.