モジュール java.base
パッケージ java.lang.foreign

インタフェースArena

すべてのスーパー・インタフェース:
AutoCloseable, SegmentAllocatorPREVIEW

public interface Arena extends SegmentAllocatorPREVIEW, AutoCloseable
Arenaは、JavaプラットフォームのプレビューAPIです。
プレビュー機能が有効な場合のみ、プログラムでArenaを使用できます。
プレビュー機能は、今後のリリースで削除するか、Javaプラットフォームの永続機能にアップグレードすることができます。
アリーナは、ネイティブ・メモリー・セグメントのライフサイクルを制御し、柔軟な割当てとタイムリな割当て解除の両方を提供します。

アリーナにはscopePREVIEWがあります - 「アリーナ・スコープ」 アリーナによって割り当てられたすべてのセグメントは、アリーナ・スコープに関連付けられます。 そのため、アリーナは、割り当てられているすべてのメモリー・セグメントの一時的な範囲を決定します。

さらに、アリーナは、割り当てられているメモリー・セグメントへのアクセスを特定のスレッドに対して「制限付き」PREVIEWにするかどうかも決定します。 アリーナはSegmentAllocatorPREVIEWで、クライアントがネイティブ・セグメントを取得するために使用できる複数の割当てメソッドを備えています。

最も単純なアリーナは、「グローバル・アリーナ」です。 グローバル・アリーナには、「無制限有効期間」があります。 そのため、グローバル・アリーナに割り当てられたネイティブ・セグメントには常にアクセス可能で、メモリーのバッキング・リージョンは割当て解除されません。 さらに、グローバル・アリーナで割り当てられるメモリー・セグメントは、どのスレッドからでも「アクセス済」PREVIEWにすることができます。

 MemorySegment segment = Arena.global().allocate(100, 1);
 ...
 // segment is never deallocated!

あるいは、クライアントは、ガベージ・コレクタによって自動的に管理される「境界有効期間」を特徴とするアリーナである「自動アリーナ」を取得できます。 そのため、次に示すように、自動アリーナで割り当てられたメモリー・バッキング・メモリー・セグメントのリージョンは、自動アリーナ (およびそれによって割り当てられたすべてのセグメント)がunreachableになったあと、未指定の時間に解放されます:

 MemorySegment segment = Arena.ofAuto().allocate(100, 1);
 ...
 segment = null; // the segment region becomes available for deallocation after this point
自動アリーナで割り当てられるメモリー・セグメントは、どのスレッドからでも「アクセス済」PREVIEWにすることもできます。

Javaランタイムの手元に割当て解除を残すのではなく、多くの場合、クライアントはメモリー・セグメントを戻すメモリーのリージョンに対する割当て解除のタイミングを制御することを希望します。 2種類のアリーナ、つまり「限定」およびsharedアリーナがサポートされています。 どちらも、手動で管理される期限付きライフ・タイムを備えています。 たとえば、限定されたアリーナの存続期間は、限定されたアリーナが作成されたときに開始され、限定されたアリーナがclosedのときに終了します。 その結果、限られたアリーナで割り当てられたメモリー・バッキング・メモリー・セグメントのリージョンは、制限されたアリーナが閉じられると割り当て解除されます。 これが発生すると、限定されたアリーナに割り当てられているすべてのセグメントが無効化され、これらのセグメントに対する後続のアクセス操作は失敗しますIllegalStateException:

 MemorySegment segment = null;
 try (Arena arena = Arena.ofConfined()) {
     segment = arena.allocate(100);
     ...
 } // segment region deallocated here
 segment.get(ValueLayout.JAVA_BYTE, 0); // throws IllegalStateException
「限定アリーナ」で割り当てられたメモリー・セグメントには、アリーナを作成したスレッドのみが(クローズ済)にアクセスできます。 複数のスレッドからメモリー・セグメントへのアクセスが必要な場合、クライアントはかわりに「共有アリーナ」内のセグメントを割り当てることができます。

様々なアリーナの特性を次の表にまとめます:

Arenasの特徴
Kind 制限付き存続期間 明示的にクローズ可能 複数のスレッドからアクセス可能
グローバル No No あり
自動 あり No あり
確定済 あり あり No
共有 あり あり あり

安全性とスレッドの制約

Arenasは強力な時間的安全保証を提供: アリーナが割り当てたメモリー・セグメントには、そのアリーナを閉じたあとはアクセスできません。 この保証を提供するコストは、アリーナによって割り当てられたメモリー・セグメントにアクセスできるスレッドの数によって異なります。 たとえば、アリーナが常に1つのスレッドによって作成およびクローズされ、そのアリーナによって割り当てられたメモリー・セグメントに常に同じスレッドからアクセスされる場合は、正確さが微妙であることを確認します。

逆に、アリーナが複数のスレッドからアクセスできるセグメントを割り当てる場合や、アクセスしているスレッド以外のスレッドでアリーナをクローズできる場合は、正確さがはるかに複雑になります。 たとえば、アリーナに割り当てられているセグメントには、whileにもう一度アクセスして、アリーナを閉じようとします。 すべてのクライアント(単純なクライアントでも)パフォーマンスへの影響を発生させることなく、強力な時間的安全保証を提供するために、領域がthread-confined領域およびshared領域に分割されます。

限られた領域で、強力なスレッド制約の保証をサポートします。 作成時に、「所有者スレッド」に割り当てられるのは通常、作成操作を開始したスレッドです。 限定されたアリーナによって作成されたセグメントは、所有者スレッドによってのみ「アクセス済」PREVIEWにできます。 さらに、所有者スレッド以外のスレッドから制限されたアリーナを閉じようとすると、WrongThreadExceptionで失敗します。

一方、共有領域には所有者スレッドがありません。 共有アリーナによって作成されたセグメントは、どのスレッドでも「アクセス済」PREVIEWにすることができます。 これは、複数のスレッドが同じメモリー・セグメントに同時に(例:パラレル処理の場合)にアクセスする必要がある場合に役立ちます。 また、共有アリーナはどのスレッドでも閉じることができます。

カスタム・アリーナ

クライアントは、より効率的な割当て戦略を実装したり、アリーナをクローズできる(だれが)をより適切に制御するために、カスタム・アリーナを定義できます。 たとえば、次のコードは、限定されたアリーナ(つまり、シングル・スレッド・アクセス)のように動作する「スライシング・アリーナ」を定義しますが、内部的に「スライシング・ロケータ」PREVIEWを使用して割当てリクエストに応答します。 スライス・アリーナが閉じられると、基礎となる限定されたアリーナも閉じられます。これにより、スライス・アリーナ(スライス・アリーナの範囲は基礎となる限定されたアリーナの範囲と同じであるため)に割り当てられているすべてのセグメントが無効になります:
class SlicingArena implements Arena {
    final Arena arena = Arena.ofConfined();
    final SegmentAllocator slicingAllocator;

    SlicingArena(long size) {
        slicingAllocator = SegmentAllocator.slicingAllocator(arena.allocate(size));
    }

    public MemorySegment allocate(long byteSize, long byteAlignment) {
        return slicingAllocator.allocate(byteSize, byteAlignment);
    }

    public MemorySegment.Scope scope() {
        return arena.scope();
    }

    public void close() {
        arena.close();
    }

}
つまり、スライス・アリーナは、非常に効率的でスケーラブルな割当て戦略を提供しながら、基礎となる限定されたアリーナによって提供されるタイムリな割当て解除保証を維持します:
try (Arena slicingArena = new SlicingArena(1000)) {
    for (int i = 0; i < 10; i++) {
        MemorySegment s = slicingArena.allocateArray(JAVA_INT, 1, 2, 3, 4, 5);
        ...
    }
} // all memory allocated is released here
実装要件:
このインタフェースの実装はスレッド・セーフです。
導入されたバージョン:
20
関連項目:
  • メソッドの詳細

    • ofAuto

      static ArenaPREVIEW ofAuto()
      ガベージ・コレクタによって自動的に管理される新しいアリーナを作成します。 返されるアリーナで割り当てられるセグメントは、どのスレッドでも「アクセス済」PREVIEWにすることができます。 返されるアリーナでclose()を呼び出すと、UnsupportedOperationExceptionになります。
      戻り値:
      ガベージ・コレクタによって自動的に管理される新しいアリーナ。
    • global

      static ArenaPREVIEW global()
      グローバル・アリーナを取得します。 グローバル・アリーナで割り当てられるセグメントは、どのスレッドでも「アクセス済」PREVIEWにすることができます。 返されるアリーナでclose()を呼び出すと、UnsupportedOperationExceptionになります。
      戻り値:
      グローバル・アリーナ。
    • ofConfined

      static ArenaPREVIEW ofConfined()
      新しい限定されたアリーナを返します。 制限されたアリーナで割り当てられたセグメントは、アリーナ(「所有者スレッド」)を作成したスレッドによって「アクセス済」PREVIEWにすることができます。
      戻り値:
      新しい限定アリーナ
    • ofShared

      static ArenaPREVIEW ofShared()
      新しい共有領域を返します。 グローバル・アリーナで割り当てられるセグメントは、どのスレッドでも「アクセス済」PREVIEWにすることができます。
      戻り値:
      新しい共有アリーナ
    • allocate

      default MemorySegmentPREVIEW allocate(long byteSize, long byteAlignment)
      指定されたサイズ(バイト単位)および整列制約(バイト単位)のネイティブ・メモリー・セグメントを返します。 返されるセグメントは、この「アリーナ・スコープ」に関連付けられます。 セグメントのaddressPREVIEWは、セグメントをバッキングするメモリーの割り当てられたオフ・ヒープ・リージョンの開始アドレスで、指定された整列制約に従ってアドレスが整列されます。
      定義:
      インタフェースSegmentAllocatorPREVIEW内のallocate
      実装要件:
      このメソッドの実装は、リクエストされたサイズを持つネイティブ・セグメントを返し、指定された整列制約と互換性がある必要があります。 さらに、このメソッドによって返される2つのセグメントS1, S2の場合、次の不変量を保持する必要があります:
          S1.asOverlappingSlice(S2).isEmpty() == true
      
      パラメータ:
      byteSize - ネイティブ・メモリー・セグメントをバッキングするメモリーのオフ・ヒープ・リージョンのサイズ(バイト単位)。
      byteAlignment - ネイティブ・メモリー・セグメントをバッキングするメモリーのオフ・ヒープ・リージョンの境界整列制約 (バイト単位)。
      戻り値:
      新しいネイティブ・メモリー・セグメント。
      throws:
      IllegalArgumentException - bytesSize < 0byteAlignment <= 0またはbyteAlignmentが2の累乗でない場合。
      IllegalStateException - このアリーナがすでにclosedである場合。
      WrongThreadException - このアリーナが制限され、このメソッドはアリーナの所有者スレッド以外のスレッドから呼び出されます。
    • scope

      arenaスコープを返します。
      戻り値:
      arenaスコープ
    • close

      void close()
      このアリーナを閉じます。 このメソッドが正常に完了すると、アリーナ・スコープはalivePREVIEWではなくなり、それに関連付けられたすべてのメモリー・セグメントにアクセスできなくなります。 さらに、このアリーナから取得したセグメントをバッキングするメモリーのオフ・ヒープ・リージョンもすべて解放されます。
      定義:
      close、インタフェースAutoCloseable
      APIのノート:
      この操作はべき等ではありません。つまり、すでに閉じているアリーナalwaysを閉じると、例外がスローされます。 これは意図的な設計の選択を反映しています: アリーナのクローズに失敗すると、基礎となるアプリケーション・ロジックにバグが表示される場合があります。
      実装要件:
      このメソッドが正常に完了した場合、this.scope().isAlive() == false 明示的なクローズ操作がサポートされていない場合は、実装でUnsupportedOperationExceptionをスローできます。
      throws:
      IllegalStateException - アリーナがすでに閉まっている場合。
      IllegalStateException - このアリーナに関連付けられたセグメントが同時にアクセスされる場合(例: 「downcallメソッド・ハンドル」PREVIEW)。
      WrongThreadException - このアリーナが制限され、このメソッドはアリーナの所有者スレッド以外のスレッドから呼び出されます。
      UnsupportedOperationException - このアリーナを明示的に閉じられない場合。
      関連項目: