モジュール jdk.incubator.foreign

パッケージ jdk.incubator.foreign

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

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


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

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など)を作成します。 また、intHandleは、パフォーマンスを向上させ、VarHandleインスタンスを介したメモリー・アクセス操作のインライン化を可能にするために、staticおよびfinalフィールドに格納されます。 次に、ヒープ外メモリーによってバッキングされるメモリー・セグメントである「ネイティブ」メモリー・セグメントを作成します。セグメントのサイズは40バイトで、プリミティブ・タイプintの10個の値を格納できます。 try-with-resources構成メンバー内にセグメントが作成されます: このイディオムにより、「Java言語仕様」14.20.3の項で説明されているセマンティクスに従って、セグメントに関連付けられているすべてのメモリー・リソースがブロックの最後に解放されます。 Try-with-resourcesブロック内で、メモリー・セグメントの内容を初期化します。特に、10個の隣接するスロットのセットとしてメモリー・セグメントを表示する場合、s[i]で、各スロットのサイズがちょうど4バイトである0 <= i < 10の場合、上記の初期化ロジックにより、s[i] = iで再度0 <= i < 10となるように各スロットが設定されます。

確定的な割当て解除位置

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

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

安全

このAPIは、メモリー・アクセスに伴って強力な安全性保証を提供します。 まず、メモリー・アドレスを使用してメモリー・セグメントを参照解除する場合、そのアドレスは(アクセス時)検証され、「外部」が参照するメモリー・セグメントの境界に配置されているメモリー・ロケーションを指していないことを確認します。 この保証「空間安全」と呼ばれます。つまり、メモリー・セグメントへのアクセスは、「Java言語仕様」15.10.4項で説明されているように、配列アクセスと同様に境界チェックされます。

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

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

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