2016-10-15 5 views
6

sun.misc.Unsafeを多用するJavaでいくつかのFFIコードを書いています。クラスの2つの実装のうちの1つを使用してコンパイルするJavaコードを書く

Java 9では、このクラスはアクセス不能になり、jdk.unsupported.Unsafeになります。今では動作するように自分のコードを書いていますが、Java 9でも引き続き動作します。

これを行うには、少なくともハッキーな方法はありますか?私はバイナリ互換性を望んでいますが、ソースの互換性も問題ありません。

編集:Unsafeのメソッドが呼び出されるたびに、反射を使用しても、仮想ディスパッチを使用しても100%ではありません。これらのメソッドのほとんどは、という単一のマシン命令でコンパイルします。したがって、パフォーマンスは本当に重要です。ラッパーを付けても構いませんが、毎回JITがインライン展開することが確実である場合に限ります。

私の現在の計画は、実行時に適切なクラスをロードすることです。

+0

「サポートされていません」... – r1verside

+0

@ r1verside私は知っていますが、それほど多くのコード(新しい開発を含む!)がそれに依存するので、ほとんど離れることはありません。 – Demi

+0

おそらく、ずっと前にやっていたはずのことをやるべきときです。コードを修正してください(あなたは古い太陽のコードを使いません)。 – Bohemian

答えて

2

一つのオプション:sun.misc.Unsafe用と1のために:あなたは、2つの実装で、あなたがへのアクセスを必要とする安全でないの方法(複数可)のための小さなシムヘルパー・インターフェースを持つことができます新しいjdk.unsupported.Unsafe。両方のクラスをJARにバイナリリソースとして保存することができ、クラス初期化中(つまり、staticブロック内)に、新しいClassLoaderを作成してshimクラスをロードできます。これは、クラスの初期化中にいくつかの反射的なオーバーヘッドを与えますが、実行時には反映が伴わず、仮想メソッドのディスパッチのみです.JITはインライン化できるはずです。

ライブラリ依存性を導入することができれば、cglibのFastClassは、基本的にこれを大幅に削減します。

このような低レベルのパフォーマンスハッキングは、常にある程度のデータが必要です。このためにJMHテストハーネスを作成し、実際には反射オーバーヘッドがであることを確認してください。が耐えられないこと、そしてJITが実際にソリューションをインライン化できることを確認してください。

0

いずれかの実装をラップするクラスを作成し、適切な実装を得るためにヘルパーメソッドを使用する方法もあります。 System.getProperties()。getProperty( "java.version")をチェックして、JDK 1.8または1.9であるかどうかを知ることができます。

実装するインタフェースはありませんので、プレーンオブジェクトのように使用する必要があります。すべての方法をラップする必要があります。たぶんもっと一般的なやり方があります。実装の

例開始

/** 
* 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

パフォーマンスについて確かですか?私の経験では、Javaによる通常の内部チェックよりもはるかに遅くはありません。 – pmcevoy12

0

あなたのライブラリがJava 9と互換性がないことを簡単に文書化し、Java 9で動作する別のバージョンブランチをリリースします(以前のバージョンでは使用できません)。これは、お客様に問題を押しのけてしまいますが、それは実際の大部分の使用事例の大部分に十分に適している可能性があります。

関連する問題