2016-10-15 1 views
6

sun.misc.Unsafe을 많이 사용하는 Java에서 일부 FFI 코드를 작성하고 있습니다.클래스의 두 구현 중 하나를 사용하여 컴파일하는 Java 코드 작성

Java 9에서이 클래스는 액세스 할 수 없으므로 jdk.unsupported.Unsafe이됩니다. 이제는 작동하도록 코드를 작성하고 싶지만 Java 9에서 계속 작업하십시오.

가장 해커가없는 방법은 무엇입니까? 바이너리 호환성을 원하지만 소스 호환성도 괜찮습니다.

편집 : Unsafe의 메소드를 호출 할 때마다 리플렉션 또는 가상 디스패치를 ​​사용하여 100 % 적합하지 않습니다. 이러한 방법의 대부분은 단일 시스템 명령어으로 컴파일됩니다. 따라서 성능이 중요합니다. 래퍼 (wrapper)를 가지고 있어도 괜찮습니다. JIT가 매번 인라인 할 것입니다.

나의 현재 계획은 런타임에 적절한 클래스를로드하는 것입니다.

+0

'지원되지 않습니다.'... – r1verside

+0

@ r1verside 알지만, 너무 많은 코드 (새로운 개발 포함)가 그것에 달려 있기 때문에 거의 사라지지 않을 것입니다. – Demi

+0

아마 오래전에해야 할 일을해야 할 때가 왔습니다. 코드를 수정하여 (낡은 태양 코드를 사용하지 않도록). – Bohemian

답변

2

하나의 옵션 : sun.misc.Unsafe에 대한 하나 하나 : 당신은 두 가지 구현과 함께, 당신은에 액세스 할 필요가 안전하지 않은의 방법 (들)에 대한 작은 심 도우미 인터페이스를 가질 수있다 새로운 jdk.unsupported.Unsafe. 두 클래스 모두 JAR에 바이너리 리소스로 저장할 수 있으며 클래스 초기화 중에 (즉, static 블록에서) 새 ClassLoader를 만들고 shim 클래스를로드 할 수 있습니다. 이것은 클래스 초기화 동안 약간의 오버 헤드를 줄지 만, 런타임에는 JIT가 인라인 할 수 있어야하는 가상 메소드 디스패치 만 반영됩니다. 하나의 구현 클래스 만로드하면됩니다.

라이브러리 의존성을 도입 할 수 있다면 cglib의 FastClass는 기본적으로 훨씬 적은 노력으로이 작업을 수행합니다.

이와 같이 낮은 수준의 성능 해킹은 언제나 그렇듯이 일부 데이터가 필요합니다. 이를위한 JMH 테스트 하네스를 생성하고 리플렉션 오버 헤드가 실제로 이고, JIT가 실제로 솔루션을 인라인 할 수 있는지 확인하십시오. 이것이 유일한 방법입니다.

0

두 가지 구현 중 하나를 랩핑하고 올바른 구현을 위해 도우미 메서드를 사용하는 클래스를 작성하는 것도 한 가지 방법입니다. 당신은 System.getProperties(). getProperty ("java.version")를 점검하여 JDK 1.8 또는 1.9에 있는지 알았거나 내가했던 것처럼 클래스를 가져 오기 위해/catch를 시도 할 수 있습니다.

구현할 인터페이스가 없으므로 일반 객체처럼 사용해야합니다. 모든 방법을 래핑해야합니다. 어쩌면 이것을하는 더 일반적인 방법이있을 것입니다. 구현의

예 시작

/** 
* A wrapper to a sun.misc.Unsafe or jdk.unsupported.Unsafe object. 
*/ 
public class MyUnsafe { 

    // the implementing class (sun.misc.Unsafe or jdk.unsupported.Unsafe) 
    private Class<?> unsafeCls; 

    // an instance of the implementing class 
    private Object unsafeObj; 

    // constructor 
    public MyUnsafe() throws InstantiationException, IllegalAccessException { 
     unsafeCls = getImplClass(); 
     unsafeObj = unsafeCls.newInstance(); 
    } 

    // get the implementing class 
    private Class<?> getImplClass() { 
     Class<?> implClass = null; 
     try { 
      // JDK 1.8 and earlier 
      implClass = Class.forName("sun.misc.Unsafe"); 
     } 
     catch (ClassNotFoundException e1) { 
      try { 
       // JDK 1.9 and later 
       implClass = Class.forName("jdk.unsupported.Unsafe"); 
      } 
      catch (ClassNotFoundException e2) { 
       // TODO - something that wraps both e1 and e2 
       throw new RuntimeException(e2); 
      } 
     } 
     return implClass; 
    } 

    // Wrap methods 

    // for example 
    public Object getObject(Object obj, long offset) throws Exception { 
     Method mtd = unsafeCls.getMethod("getObject", new Class<?>[] { Object.class, long.class }); 
     return mtd.invoke(unsafeObj, new Object[] { obj, offset }); 
    } 

    // and so on... 
} 
+1

그건 작동하지 않습니다. 각 메서드 호출에 대한 반사 오버 헤드로 인해 성능이 저하됩니다. JIT가 래퍼를 인라인 할 수있는 무언가가 필요하다. JDK 버전에 따라 하나의 클래스 또는 다른 클래스를로드하는 선을 따른다. – Demi

+0

성능에 대한 확신이 있습니까? 내 경험에 의하면 자바에 의해 수행되는 일반적인 내부 검사보다 훨씬 느리다. – pmcevoy12

0

저급 기술 솔루션은 물론 라이브러리가 Java 9와 호환되지 않는다는 것을 문서화하고 Java 9에서 작동하는 별도의 버전 분기 (이전 버전에는없는)를 릴리스하는 것입니다. 이것은 고객에게 문제를 푸시하지만 실제 사용 사례의 대다수에 충분히 적합 할 것입니다.

관련 문제