- すべてのスーパー・インタフェース:
AutoCloseable
MemorySegment
)は、リソース・スコープがalive (isAlive()
を参照してください)である間、およびリソース・スコープ(もしあれば)に関連付けられたスレッドによってのみアクセスできます。
明示的なリソース・スコープ
newConfinedScope()
、newSharedScope()
サポート「確定的割当解除」から取得されたリソース・スコープ。これらのリソース・スコープを「明示的なスコープ」と呼びます。 明示的なリソース・スコープは、明示的に(close()
を参照してください)を終了できます。 リソース・スコープがクローズされると、aliveではなくなります(isAlive()
を参照)。そのスコープ(例: MemorySegment
インスタンスへのアクセスの試行)に関連付けられたリソースに対する後続の操作は、IllegalStateException
で失敗します。
リソース・スコープを閉じると、そのスコープ(addCloseAction(Runnable)
を参照してください)に関連付けられたすべてのクリーンアップ・アクションが呼び出されます。 さらに、リソース・スコープを閉じると、そのスコープに関連付けられた基礎となるメモリー・リソースの解放がトリガーされる可能性があります。たとえば、次のようになります:
- ネイティブ・メモリー・セグメントに関連付けられたスコープをクローズすると、(
MemorySegment.allocateNative(long, ResourceScope)
またはSegmentAllocator.arenaAllocator(ResourceScope)
を参照してください)に関連付けられたネイティブ・メモリーが「解放」になります - マップされたメモリー・セグメントに関連付けられたスコープをクローズすると、バッキング・メモリー・マップ・ファイルがマップ解除されます(
MemorySegment.mapFile(Path, long, long, FileChannel.MapMode, ResourceScope)
を参照してください) - アップ・コール・スタブに関連付けられているスコープをクローズすると、スタブが解放されます(
CLinker.upcallStub(MethodHandle, FunctionDescriptor, ResourceScope)
を参照)
明示的なスコープをCleaner
インスタンス(newConfinedScope(Cleaner)
およびnewSharedScope(Cleaner)
を参照してください)に関連付けることができます。 これらのリソース・スコープは、managedリソース・スコープと呼ばれます。 管理対象リソース・スコープは、スコープ・インスタンスがunreachableになると自動的にクローズされます。
管理対象スコープは、予測可能な確定的リソースの割り当て解除を可能にしつつ、偶発的なネイティブ・メモリー・リークを防ぐために役立ちます。 管理対象リソース・スコープが明示的にクローズされている場合、スコープが到達不能になると、それ以上のアクションは実行されません。つまり、管理対象かどうかに関係なく、リソース・スコープに関連付けられたクリーンアップ・アクション(addCloseAction(Runnable)
を参照してください)は「1回のみ」と呼ばれます。
暗黙的なリソース・スコープ
newImplicitScope()
から取得したリソース・スコープを明示的にクローズすることはできません。 これらのリソース・スコープを「暗黙的なスコープ」と呼びます。 暗黙的なリソース・スコープでclose()
をコールすると、常に例外が発生します。 暗黙的なスコープに関連付けられたリソースは、スコープ・インスタンスがunreachableになると解放されます。
重要な暗黙的なリソース・スコープは「グローバル・スコープ」というものです。グローバル・スコープは、unreachableになることが保証される暗黙的なスコープです。 結果として、グローバル・スコープはそれに関連付けられたリソースの解放を試行しません。 このようなリソースは、必要に応じてクライアントから独立して管理する必要があります。
スレッド制限
リソース・スコープは、さらに2つのカテゴリに分けることができます: thread-confinedリソース・スコープおよびsharedリソース・スコープ。
限定されたリソース・スコープ(newConfinedScope()
を参照してください)は、強力なスレッド限定保証をサポートします。 作成時に、「所有者スレッド」(通常は作成操作(ownerThread()
を参照してください)を開始したスレッド)が割り当てられます。 限定されたリソース・スコープを作成すると、所有者スレッドのみが、このリソース・スコープに関連付けられたリソースを直接操作できます。 所有者スレッド以外のスレッドからリソース・アクセスを実行しようとすると、実行時エラーが発生します。
一方、共有リソース・スコープ(newSharedScope()
およびnewImplicitScope()
を参照)には所有者スレッドがありません。この共有リソース・スコープに関連付けられたリソースは、複数のスレッドからアクセスできます。 これは、複数のスレッドが同じリソース (例:パラレル処理の場合)に同時にアクセスする必要がある場合に役立ちます。 たとえば、クライアントが共有セグメントからSpliterator
を取得すると、セグメントをスライスし、複数のスレッドを分離したセグメント・スライスに対して並行して作業できます。 次のコードを使用すると、メモリー・セグメント内のすべてのint値を並列に合計できます:
SequenceLayout SEQUENCE_LAYOUT = MemoryLayout.sequenceLayout(1024, MemoryLayouts.JAVA_INT); try (ResourceScope scope = ResourceScope.newSharedScope()) { MemorySegment segment = MemorySegment.allocateNative(SEQUENCE_LAYOUT, scope); VarHandle VH_int = SEQUENCE_LAYOUT.elementLayout().varHandle(int.class); int sum = StreamSupport.stream(segment.spliterator(SEQUENCE_LAYOUT), true) .mapToInt(s -> (int)VH_int.get(s.address())) .sum(); }
強力な共有リソース・スコープは慎重に使用する必要があります: 別のスレッドからスコープがクローズされている間に共有スコープに関連付けられたリソースにアクセスする場合、アクセス・スレッドとクローズ・スレッドの両方で例外が発生する可能性があります。 クライアントは、共有リソース・スコープを繰り返し (例:例外がスローされなくなるまでclose()
をコールし続ける)を閉じようとしないでください。 かわりに、共有リソース・スコープのクライアントでは、共有リソース・スコープをクローズするスレッドが、同じスコープによって管理されるリソースにアクセスしているスレッドに対して競合しないように、適切な同期メカニズム(例:リソース・スコープ・ハンドルの使用)が必ず配置されるようにする必要があります。
リソース・スコープ・ハンドル
リソース・スコープは、1つ以上のリソース・スコープ「ハンドル」を取得することでnon-closeableにできます(acquire()
を参照)。 リソース・スコープ・ハンドルを使用して、特定のリソース・スコープ(明示的または暗黙的)に関連付けられたリソースを一定期間解放できないことを確認できます - 例:スコープに関連付けられた1つ以上のリソースを含むコードの重要なリージョン中。 たとえば、明示的なリソース・スコープは、そのスコープに対して取得されたすべてのハンドルが(close()
を参照してください)をクローズした後にのみクローズできます。 これは、クライアントがメモリー・セグメントに対して重要な操作を実行する必要があるときに、セグメントが解放されないようにする必要がある場合に便利です。次のように実行できます:
暗黙的なリソース・スコープの取得も可能ですが、多くの場合、不必要ではありません: 暗黙的なスコープに関連付けられたリソースは、スコープがunreachableになった場合にのみ解放されるため、クライアントはMemorySegment segment = ... ResourceScope.Handle segmentHandle = segment.scope().acquire() try { <critical operation on segment> } finally { segment.scope().release(segmentHandle); }
Reference.reachabilityFence(Object)
のように、暗黙的なスコープに関連付けられたリソースが途中でリリースされていないことを確認できます。 つまり、前述のコード・スニペットは、暗黙的なスコープに対して(トリビアル)も機能します。 - 実装要件:
- このインタフェースの実装は不変、スレッド・セーフ、およびvalue-basedです。
-
ネストされたクラスのサマリー
-
メソッドのサマリー
修飾子と型メソッド説明acquire()
このリソース・スコープに関連付けられたリソース・スコープ・ハンドルを取得します。void
addCloseAction
(Runnable runnable) リソース・スコープがクローズされたときに実行されるカスタム・クリーンアップ・アクションを追加します。void
close()
このリソース・スコープを閉じます。static ResourceScope
常に有効とみなされる暗黙的なスコープを返します。boolean
isAlive()
このリソース・スコープは稼働していますか。boolean
このリソース・スコープは「暗黙的なスコープ」ですか。static ResourceScope
新しい限定スコープを作成します。static ResourceScope
newConfinedScope
(Cleaner cleaner) Cleaner
によって管理される新しい限定スコープを作成します。static ResourceScope
新しい「暗黙的なスコープ」を作成します。static ResourceScope
新しい共有スコープを作成します。static ResourceScope
newSharedScope
(Cleaner cleaner) Cleaner
によって管理される新しい共有スコープを作成します。このリソース・スコープを所有するスレッド。void
release
(ResourceScope.Handle handle) 指定されたリソース・スコープ・ハンドルを解放します。
-
メソッドの詳細
-
isAlive
boolean isAlive()このリソース・スコープは稼働していますか。- 戻り値:
- true。このリソース・スコープが存続している場合。
- 関連項目:
-
ownerThread
Thread ownerThread()このリソース・スコープを所有するスレッド。- 戻り値:
- このリソース・スコープを所有するスレッド、またはこのリソース・スコープが共有されている場合は
null
。
-
isImplicit
boolean isImplicit()このリソース・スコープは「暗黙的なスコープ」ですか。- 戻り値:
- このスコープが「暗黙的なスコープ」の場合はtrue。
- 関連項目:
-
close
void close()このリソース・スコープを閉じます。 副作用として、この操作が例外なく完了した場合、このスコープは「生きていない」としてマークされ、このスコープに関連付けられたリソースに対する後続の操作はIllegalStateException
で失敗します。 また、クローズが成功すると、このリソース・スコープに関連付けられたすべてのネイティブ・リソースが解放されます。- 定義:
close
、インタフェースAutoCloseable
- APIのノート:
- この操作はべき等ではありません。つまり、すでに閉じているリソース・スコープalwaysをクローズすると、例外がスローされます。 これは意図的な設計の選択を反映しています: リソース・スコープの状態遷移はクライアント・コードでマニフェストである必要があります。これらの遷移のいずれかが失敗すると、基礎となるアプリケーション・ロジックのバグが表示されます。
- 例外:
IllegalStateException
- 次の条件のいずれかが満たされた場合:UnsupportedOperationException
- このリソース・スコープがimplicitの場合。
-
addCloseAction
void addCloseAction(Runnable runnable) リソース・スコープがクローズされたときに実行されるカスタム・クリーンアップ・アクションを追加します。 スコープがクローズされると、カスタム・クリーンアップ・アクションが起動される順序は指定されません。- パラメータ:
runnable
- このスコープに関連付けられるカスタム・クリーンアップ・アクション。- 例外:
IllegalStateException
- このスコープがすでにクローズされている場合。
-
acquire
ResourceScope.Handle acquire()このリソース・スコープに関連付けられたリソース・スコープ・ハンドルを取得します。 明示的なリソース・スコープは、それから取得されたすべてのリソース・スコープ・ハンドルがrelease(Handle)リリースされるまでclosedにできません。- 戻り値:
- リソース・スコープ・ハンドル。
-
release
void release(ResourceScope.Handle handle) 指定されたリソース・スコープ・ハンドルを解放します。 このメソッドはべき等であり、同じハンドルを複数回リリースしても効果はありません。- パラメータ:
handle
- リリースするリソース範囲ハンドル。- 例外:
IllegalArgumentException
- 指定されたハンドルがこのスコープに関連付けられていない場合。
-
newConfinedScope
static ResourceScope newConfinedScope()新しい限定スコープを作成します。 結果のスコープはクローズ可能で、Cleaner
によって管理されません。- 戻り値:
- 新しい限定スコープ。
-
newConfinedScope
static ResourceScope newConfinedScope(Cleaner cleaner) Cleaner
によって管理される新しい限定スコープを作成します。- パラメータ:
cleaner
- 返されたスコープに関連付けられるクリーナ。- 戻り値:
cleaner
によって管理される新しい限定スコープ。- 例外:
NullPointerException
-cleaner == null
の場合。
-
newImplicitScope
static ResourceScope newImplicitScope()新しい「暗黙的なスコープ」を作成します。 暗黙的なスコープは、「暗黙的なクローズ」のみの機能を持つ管理、共有および非クローズ可能なスコープです。 暗黙的なスコープはガベージ・コレクタによって暗黙的にクローズできるため、不要なメモリー・プレッシャを避けるために、割当て解除パフォーマンスが重要な問題ではない場合にのみ暗黙的なスコープを使用することをお薦めします。- 戻り値:
- 新しい暗黙的なスコープ。
-
globalScope
static ResourceScope globalScope()常に有効とみなされる暗黙的なスコープを返します。- 戻り値:
- グローバル・スコープ。
-