2011-10-28 4 views
6

나는 sun.misc.Unsafe의 문서를 이해하는 데 어려움을 겪고있다. 일반적인 용도로 사용되지는 않았으므로 누구도 읽을 수 없도록 만들지는 않았지만 실제로는 배열의 요소 (그래서 포인터를 네이티브 코드에 전달할 수 있음). 누구든지이 작업을 수행하는 코드가 있습니까? 믿을만한가요?sun.misc.Unsafe를 사용하여 Java 배열 항목의 주소를 가져 오시겠습니까?

+0

http://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe –

+0

[개발자가 프로그램을 작성해야하는 이유 전화 '태양'패키지] (http://www.oracle.com/) .com/technetwork/java/faq-sun-packages-142232.html) – BalusC

+0

imo, unsafe doc은 꽤 좋지만 어쨌든 일반 대중을위한 것은 아닙니다. 몇 가지 지침이 필요하면 java.util.concurrent와 java.util.concurrent.atomic 읽기 시작하십시오. unsafe는 C (또는 원하는 경우 어셈블러)와 매우 비슷합니다. 만약 경험이 없다면 안전하지 않은 것이 아닙니다. Java 코드를 분해하는 방법 : http://wikis.sun.com/display/HotSpotInternals/PrintAssembly – bestsss

답변

6

배열을 사용하는 대신 ByteBuffer.allocateDirect() 직접 버퍼를 사용할 수 있습니다. 이것은 필드에 주소를 가지며이 주소는 ByteBuffer의 수명 동안 변경되지 않습니다. 직접 ByteBuffer는 최소의 힙 공간을 사용합니다. 리플렉션을 사용하여 주소를 가져올 수 있습니다.


Unsafe를 사용하여 주소를 가져올 수 있지만 문제는 GC가 언제든지 이동할 수 있다는 것입니다. 객체는 메모리에 고정되어 있지 않습니다.

JNI에서는 특수한 방법을 사용하여 Java 객체간에 데이터를 복사하여이 문제 (및 기타 문제)를 피할 수 있습니다. C 코드로 객체간에 데이터를 교환하려면 이러한 메소드를 사용하는 것이 좋습니다.

+1

바이트 배열이라는 용어로 정의 된 기존 API를 구현하려고 할 때 직접 바이트 버퍼 (문제를 쉽게 해결할 수 있음)를 사용하지 않으려 고하고 복사의 페널티를 피하려고합니다. 여분의 버퍼 세트로부터. 이것은 최후의 수단으로 충분하지만 더 나은 방법이 있어야합니다. JNI를 사용하면 더 쉽게 작업 할 수 있지만 불행히도 전체 배열 작업 이외의 작업을 수행하는 데 필요한 인터페이스가없는 JNA와 함께 작업하고 있습니다. – Jules

+0

@Jules, JNI는 GC를 손상시킬 수있는'GetPrimitiveArrayCritical '이있는 경우를 제외하고는 자체적으로 복사본을 생성합니다. 글 머리 기호를 물고 직접 (버퍼) 메모리로 복사하십시오. 그게 유일한 실현 가능한 해결책입니다. 예를 들어 impl. FileOutputStream (SocketOutputStream extends)은 스택에있는 요소의 복사본을 사용합니다. 가장 높은 비용은 어느 쪽이든 지불해야하는 데이터 (및 캐시 미스, 심지어)의로드 비용과 함께 발생하기 때문에 복사에 대한 처벌은 그다지 높지 않습니다. 복사하면 캐시 라인을 미리 가져 오게되므로 원시 코드의 작동 방식을 더 잘 파악하지 못하는 것일 수 있습니다. – bestsss

+0

@Jules, 사이드 노트 : javax.net.ssl.SSLEngine조차도 버퍼를 사용할 수 있으며, 모든 알고리즘은 byte []이며 직접 버퍼를 임시 배열에 복사하는 결과를 낳습니다. 이것은 역 이야기이며 도덕적입니다. SSLEngine에 의한 직접 버퍼를 사용하지 않는다. – bestsss

6

다음은 작동하는 샘플입니다. JVM을 부적절하게 사용하여 Unsafe 클래스를 쉽게 크래시 할 수 있으므로주의하십시오.

import java.lang.reflect.Field; 

import sun.misc.Unsafe; 

public class UnsafeTest { 

    public static void main(String... args) { 
     Unsafe unsafe = null; 

     try { 
      Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); 
      field.setAccessible(true); 
      unsafe = (sun.misc.Unsafe) field.get(null); 
     } catch (Exception e) { 
      throw new AssertionError(e); 
     } 

     int ten = 10; 
     byte size = 1; 
     long mem = unsafe.allocateMemory(size); 
     unsafe.putAddress(mem, ten); 
     long readValue = unsafe.getAddress(mem); 
     System.out.println("Val: " + readValue); 

    } 
} 
+2

그 코드는 DirectByteBuffer가 어떻게 작동하는지 완벽하게 안전해야합니다. 불행히도 기존 배열의 데이터에 액세스하는 것은 내가 원하는 작업을 수행하지 않습니다. – Jules

+4

@StephenC, 코드는 완벽하게 괜찮습니다. 기본적으로'char * mem = malloc (size); ... '은 GC에 의해 결코 건드리지 않으며, 리얼하지 않는 한 네이티브 C 누출을 일으 킵니다. – bestsss

+2

코드는 괜찮지 만 할당 된 메모리를 확보하는 것도 고려해야합니다. DirectByteBuffer를 참조 해주세요. 또한 할당 된 메모리가 0이 아니므로 직접 배열이 0으로 초기화되었다고 가정 할 수 없습니다. –

1

왜? Java 배열의 내용을 다루는 JNI에는 많은 기능이 있습니다. 다음 주에는 없을 수도있는 문서화되지 않은 내부 Sun 클래스를 사용할 필요가 없습니다.

+0

JNI 대신 JNA를 사용하고 있는데, 인터페이스와 연결되는 함수는 배열의 중간에 포인터를 전달해야하지만 JNA는 배열의 시작 부분에 대한 포인터를 생성 할 수있는 것처럼 보입니다. – Jules

+0

@Jules, JNA와 일반 배열을 섞지 말고 직접 버퍼를 사용하십시오. – bestsss

관련 문제