2011-10-28 14 views
6

私はsun.misc.Unsafeの文書を理解するのに苦労しています - それは一般的な使用を意図していないと私は推測するが、誰も実際にそれが読みやすくて気にしないです - しかし、私は実際には本当にのアドレスを見つける方法が必要です配列の要素(ネイティブコードにポインタを渡すことができるように)。誰もこれを行う作業コードを持っていますか?それは信頼できますか?ここでsun.misc.Unsafeを使用してJava配列項目のアドレスを取得しますか?

+0

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

+0

[なぜ開発者はプログラムを書くべきでないのですか?] 「Sun 'Packages」(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コードの逆アセンブルし取得する方法:あなたは(つまり、それについてのSOに質問をしていないものを知っていればhttp://wikis.sun.com/display/HotSpotInternals/PrintAssembly – bestsss

答えて

6

配列を使用する代わりに、ByteBuffer.allocateDirect()ダイレクトバッファを使用できます。これはフィールド内のアドレスを持ち、このアドレスはByteBufferの寿命の間は変化しません。直接のByteBufferは最小限のヒープスペースを使用します。リフレクションを使用してアドレスを取得できます。


Unsafeを使用してアドレスを取得することはできますが、問題はGCがいつでも移動できることです。オブジェクトはメモリに固定されていません。

あなたがこの問題(およびその他)を避けるために、Javaオブジェクトから/にデータをコピーするために特別なメソッドを使用することができますJNIで

私はあなたのCコードとオブジェクトの間でデータを交換したい場合は、これらを使用することをお勧め。

+1

バイト配列の観点から定義されている既存のAPIを実装しようとしているので、直接バイトバッファ(むしろ問題を簡単に解決できるようになります)を使用するのではなく、コピーのペナルティを避けようとしていますバッファの余分なセットから。これは最後の手段としては十分ですが、よりよい方法が必要です。 JNIを使​​用すると、これは簡単になりますが、残念ながら私はJNAを使用しています.JNAは、配列全体を処理するために必要なインタフェースを備えていないようです。 – Jules

+0

@Jules、JNIはGCを傷つける可能性のある 'GetPrimitiveArrayCritical'を付けたい場合を除き、それ自身でコピーを生成します。弾丸を噛んで、直接(バッファ)メモリにコピーします。これが唯一実現可能な解決策です。例えば、インプラント。 FileOutputStream(SocketOutputStream extends)は、スタック上の要素のコピーを使用します。コピーのペナルティはそれほど高くはありません。なぜなら、いずれかの方法で支払う必要があるデータ(およびキャッシュミス)の負担コストが最も高いからです。コピーするとキャッシュラインもプリフェッチされるので、ネイティブコードがどのように機能しているかをさらによく見極めることができます。 – bestsss

+0

@Jules、サイドノート:javax.net.ssl.SSLEngineでさえバッファの使用が許可され、すべてのアルゴリズムがbyte []であり、ダイレクトバッファを一時配列にコピーすることになります。これは逆の話であり、その道徳ですSSLEngineを使用しない直接バッファを使用しないでください。 – bestsss

6

は、作業サンプルです。しかし、あなたは、Unsafeクラスの不適切な使い方であなたのJVMを簡単にクラッシュさせるかもしれないので注意してください。

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には決して触れません。 – bestsss

+2

コードは問題ありませんが、割り当てられたメモリを解放することも検討する必要があります。 DirectByteBufferを参照してください。また、割り当てられたメモリがゼロにならないので、ダイレクト・アレイがゼロで初期化されていると仮定することはできません。 –

1

なぜですか? JNIには、Java配列の内容を扱うための多くの機能があります。あなたは、来週にはないかもしれない、文書化されていない社内Sunクラスを使う必要はありません。

+0

私はJNIではなくJNAを使用していますが、インタフェースの関数は、ポインタを配列の途中に渡す必要がありますが、JNAは配列の先頭へのポインタしか生成できないようです。 – Jules

+0

@Jules、JNAと通常の配列を混用しないでください。直接バッファを使用してください。 – bestsss

関連する問題