モジュール jdk.incubator.foreign

パッケージ jdk.incubator.foreign

下位レベルの安全かつ効率的なメモリー・アクセスをサポートするクラスです。 次に例を示します。


static final VarHandle intHandle = MemoryHandles.varHandle(int.class, ByteOrder.BIG_ENDIAN);

try (MemorySegment segment = MemorySegment.allocateNative(10 * 4)) {
   MemoryAddress base = segment.baseAddress();
   for (long i = 0 ; i < 10 ; i++) {
     intHandle.set(base.addOffset(i * 4), (int)i);
   }
 }
 
次に、任意のメモリーのロケーションでプリミティブ・タイプintの値を操作するためのvarハンドル(intHandleなど)を作成します。 次に、ヒープ外メモリーによってバッキングされるメモリー・セグメントである「ネイティブ」メモリー・セグメントを作成します。セグメントのサイズは40バイトで、プリミティブ・タイプintの10個の値を格納できます。 try-with-resources構成メンバー内にセグメントが作成されます: このidiomによって、セグメントに関連するすべてのメモリー・リソースがブロックの最後に解放されます。 Try-with-resourcesブロック内で、メモリー・セグメントの内容を初期化します。特に、10個の隣接するスロットのセットとしてメモリー・セグメントを表示する場合、s[i]で、各スロットのサイズがちょうど4バイトである0 <= i < 10の場合、上記の初期化ロジックにより、s[i] = iで再度0 <= i < 10となるように各スロットが設定されます。

このパッケージによって導入される主な抽象化は、MemorySegmentおよびMemoryAddressです。 1つ目は、連続するメモリー・リージョンをモデル化するもので、Javaヒープの内部にも外部にも配置できます。後者が、アドレスをモデル化します。 - つまり、特定のセグメント内のオフセットです。 メモリー・アドレスは、MemoryHandlesクラスで定義されたcombinatorメソッドを使用して取得できる、メモリー・アクセスvarハンドルの主なアクセス座標を表します。 さらに、MemoryLayoutクラス階層では、「メモリー・レイアウト」の記述および特定のレイアウトのバイト単位のサイズの計算、その位置合せ要件の取得などの基本的な操作を実行できます。 また、メモリー・レイアウトは、別のより抽象的な方法を提供し、メモリー・アクセス変数ハンドルを生成します(レイアウト・パスの使用など)。

確定的な割当て解除位置

メモリー・セグメントを操作するコードを記述する場合、特にJavaヒープの外部にあるメモリーでバックアップする場合、MemorySegment.close()メソッドを明示的に、または暗黙的に、(前述の例で示したように)リソースを構成することによって、セグメントが使用されなくなったときにメモリー・セグメントに関連付けられているリソースが解放されることが重要です。 特定のメモリー・セグメントのクローズは、成功する「原子性」操作です - そして、セグメントに関連付けられている基本的なメモリーが解放されるか、または「失敗」に例外が発生します。

決定論的な割当て解除モデルは、他のAPIに導入された暗黙的な戦略とは大幅に異なるもので、ほとんどの場合ByteBuffer API: その場合、ネイティブ・バイト・バッファが(ByteBuffer.allocateDirect(int)を参照してください)で作成されると、バイト・バッファ参照がunreachableになるまで、基礎となるメモリーは解放されません。 このような暗黙的な割当て解除モデルは非常に便利ですが、 - クライアントは、「閉じる」に直接バッファを覚えている必要はありません。 - また、このようなモデルでは、ダイレクト・バッファに関連付けられたメモリーが実際に解放されていることをクライアント側でハードにできます。

安全

このAPIは、メモリー・アクセスに伴って強力な安全性保証を提供します。 まず、メモリー・アドレスを使用してメモリー・セグメントを参照解除する場合、そのアドレスは(アクセス時)検証され、「外部」が参照するメモリー・セグメントの境界に配置されているメモリー・ロケーションを指していないことを確認します。 ここでは、この保証「空間安全」を呼び出します。

メモリー・セグメントは(前述を参照)を閉じることができるため、メモリー・アドレスも(アクセス時)により検証され、属しているセグメントが早期に閉じられていないことが確認されます。 ここでは、この保証「時間的安全」を呼び出します。 一般的には、複数のスレッドが同じメモリー・セグメントに同時にアクセスまたはクローズ(あるいはその両方)を試みるため、時間的安全性を確保するのは困難な場合があります。 メモリー・アクセスAPIは、メモリー・セグメントについての強力なthread-confinementの保証を認識することで、この問題に対処: 各メモリー・セグメントは、所有者スレッド(セグメントにアクセスまたはクローズできる唯一のスレッド)に関連付けられます。 所有者スレッド以外のスレッドは、使用するためにセグメントを明示的にacquireacquireする必要があります。

空間安全と時間的安全性を組み合せると、各メモリー・アクセス操作が成功することを確認できます - および有効なメモリーのロケーションにアクセス - または失敗。

  • インタフェースのサマリー 
    インタフェース 説明
    MemoryAddress
    メモリー・アドレスは、指定のMemorySegment内のオフセットをエンコードします。
    MemoryLayout
    メモリー・レイアウトを使用すると、「言語選択なし」方式でメモリー・セグメントのコンテンツを記述できます。
    MemoryLayout.PathElement
    このクラスのインスタンスは、レイアウト・パスの形成に使用されます。
    MemorySegment
    メモリー・セグメントは、連続するメモリー・リージョンをモデル化します。
  • クラスのサマリー 
    クラス 説明
    GroupLayout
    グループ・レイアウトは、複数の「メンバー・レイアウト」を結合するために使用します。
    MemoryHandles
    このクラスは、メモリー・アクセス変数ハンドルを構成および結合するためのいくつかのファクトリ・メソッドを定義します。
    MemoryLayouts
    このクラスは、便利なレイアウト定数を定義します。
    SequenceLayout
    順序レイアウト。
    ValueLayout
    値レイアウト。