- すべてのスーパー・インタフェース:
AutoCloseable
MemorySegment
)には、リソース・スコープがaliveであり、リソース・スコープ(もしあれば)に関連付けられた「スレッド」によってのみアクセスできます。
確定的な割当て解除位置
リソース・スコープは「確定的割当て解除」をサポートしています。つまり、明示的にclosedにできます。 リソース・スコープがクローズされると、alive
ではなくなり、そのスコープ(例: MemorySegment
インスタンスへのアクセスを試行しています)に関連付けられたリソースに対する後続の操作はIllegalStateException
で失敗します。
リソース・スコープをクローズすると、そのスコープに関連付けられたすべての「クローズ処理」がコールされます。 さらに、リソース・スコープを閉じると、そのスコープに関連付けられた基礎となるメモリー・リソースの解放がトリガーされる可能性があります。たとえば、次のようになります:
- 「ネイティブ・メモリー・セグメント」に関連付けられたスコープを閉じると、それに関連付けられたネイティブ・メモリーが「解放」になります
- 「マップされたメモリー・セグメント」に関連付けられたスコープを閉じると、バッキング・メモリー・マップ・ファイルがマップ解除されます
- 「アップ・コール・スタブ」に関連付けられたスコープをクローズすると、スタブが解放されます
- 「変数アリティ・リスト」に関連付けられたスコープを閉じると、その可変アリティ・リスト・インスタンスに関連付けられたメモリーが解放されます。
暗黙的な割当て解除
リソース・スコープをCleaner
インスタンスに関連付けることができるため、スコープ・インスタンスがunreachableになったら、リソース・スコープも自動的にクローズされます。 これは、偶発的なネイティブ・メモリー・リークを防止しながら、予測可能な確定的リソース・ロケーションを許可するのに役立ちます。 管理対象リソース・スコープが明示的にクローズされている場合、スコープが到達不能になったとき、つまり、リソース・スコープに関連付けられた「クローズ処理」は「正確に1回」と呼ばれます。
グローバル・スコープ
重要な暗黙的なリソース・スコープは「グローバル・スコープ」と呼ばれ、グローバル・スコープは、明示的にまたは暗黙的にクローズできないリソース・スコープです。 そのため、グローバル・スコープは、それに関連付けられたリソースの解放を試行しません。 グローバル・スコープに関連付けられたリソースの例を次に示します:- 「配列」または「バッファ」から作成されたヒープ・セグメント
- 変数アリティは、RAWメモリー・アドレスから「取得」をリスト
- ネイティブ・シンボル「取得」 (「ローダー・ルック・アップ」から、または
CLinker
から)。
スレッド制限
リソース・スコープは2つのカテゴリに分類できます: thread-confinedリソース・スコープおよびsharedリソース・スコープ。「限られたリソース・スコープ」は、強力なスレッド限定保証をサポートします。 作成時に、「所有者スレッド」(通常は作成操作を開始したスレッド)が割り当てられます。 限定されたリソース・スコープを作成すると、所有者スレッドのみが、このリソース・スコープに関連付けられたリソースを直接操作できます。 所有者スレッド以外のスレッドからリソース・アクセスを実行しようとすると、実行時エラーが発生します。
一方、「共有リソース・スコープ」には所有者スレッドがありません。つまり、共有リソース・スコープに関連付けられたリソースには複数のスレッドからアクセスできます。 これは、複数のスレッドが同じリソース (例:パラレル処理の場合)に同時にアクセスする必要がある場合に役立ちます。 たとえば、クライアントは共有スコープによってバックアップされたセグメントからSpliterator
を取得し、そのセグメントをスライスするために使用し、複数のスレッドを非結合セグメント・スライスでパラレルに動作させることができます。 次のコードを使用すると、メモリー・セグメント内のすべてのint値を並列に合計できます:
try (ResourceScope scope = ResourceScope.newSharedScope()) {
SequenceLayout SEQUENCE_LAYOUT = MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_INT);
MemorySegment segment = MemorySegment.allocateNative(SEQUENCE_LAYOUT, scope);
int sum = segment.elements(ValueLayout.JAVA_INT).parallel()
.mapToInt(s -> s.get(ValueLayout.JAVA_INT, 0))
.sum();
}
共有リソース・スコープは強力ですが、注意して使用する必要があります: スコープが別のスレッドからクローズされている間に、1つ以上のスレッドが共有スコープに関連付けられたリソースにアクセスした場合、アクセス・スレッドとクローズ・スレッドの両方で例外が発生する可能性があります。 クライアントは、共有リソース・スコープを繰り返し (例:例外がスローされなくなるまでclose()
をコールし続ける)を閉じようとしないでください。 かわりに、共有リソース・スコープのクライアントは、共有リソース・スコープをクローズするスレッドが同じスコープで管理されるリソースにアクセスするスレッドに対して競合しないように、常に適切な同期メカニズム(たとえば、一時的な依存関係の使用については、次を参照してください)が配置されるようにする必要があります。
一時的な依存関係
リソース・スコープは互いに依存できます。 さらに具体的には、スコープは、1つ以上の他のリソース・スコープで「一時的な依存関係」を機能させることができます。 このようなリソース・スコープは、allが依存するスコープもクローズされるまで(暗黙的または明示的に)をクローズできません。これは、クライアントがメモリー・セグメントに対して重要な操作を実行する必要がある場合に便利です。その間に、そのセグメントに関連付けられたスコープが閉じないようにする必要があります。これは、次のように実行できます:
MemorySegment segment = ...
try (ResourceScope criticalScope = ResourceScope.newConfinedScope()) {
criticalScope.keepAlive(segment.scope());
<critical operation on segment>
}
- 実装要件:
- このインタフェースの実装は不変、スレッド・セーフ、およびvalue-basedです。
-
メソッドのサマリー
修飾子と型メソッド説明void
addCloseAction
(Runnable runnable) リソース・スコープがクローズされたときに実行されるカスタム・クリーンアップ・アクションを追加します。void
close()
このリソース・スコープを閉じます。static ResourceScope
「グローバル・スコープ」を返します。boolean
isAlive()
このリソース・スコープが存続している場合、true
を返します。void
keepAlive
(ResourceScope target) このスコープとターゲット・スコープの間に一時的な依存関係を作成します。static ResourceScope
新しい限定スコープを作成します。static ResourceScope
newConfinedScope
(Cleaner cleaner) 提供されたクリーナ・インスタンスによって管理される、新しい限定されたスコープを作成します。static ResourceScope
プライベートCleaner
インスタンスによって管理される新しい共有スコープを作成します。static ResourceScope
新しい共有スコープを作成します。static ResourceScope
newSharedScope
(Cleaner cleaner) 提供されたクリーナ・インスタンスによって管理される新しい共有スコープを作成します。このリソース・スコープを所有するスレッド。
-
メソッドの詳細
-
isAlive
boolean isAlive()このリソース・スコープが存続している場合、true
を返します。- 戻り値:
true
:このリソース・スコープが存続している場合- 関連項目:
-
ownerThread
Thread ownerThread()このリソース・スコープを所有するスレッド。- 戻り値:
- このリソース・スコープを所有するスレッド、またはこのリソース・スコープが共有されている場合は
null
。
-
close
void close()このリソース・スコープを閉じます。 副作用として、この操作が例外なしで完了した場合、このスコープは「生きていない」としてマークされ、このスコープに関連付けられたリソースに対する後続の操作はIllegalStateException
で失敗します。 また、クローズが成功すると、このリソース・スコープに関連付けられたすべてのネイティブ・リソースが解放されます。- 定義:
close
、インタフェース:AutoCloseable
- APIのノート:
- この操作はべき等ではありません。つまり、すでに閉じているリソース・スコープalwaysをクローズすると、例外がスローされます。 これは意図的な設計の選択を反映しています: リソース・スコープの状態遷移はクライアント・コードでマニフェストである必要があります。これらの遷移のいずれかが失敗すると、基礎となるアプリケーション・ロジックのバグが表示されます。
- 例外:
IllegalStateException
- 次の条件のいずれかが満たされた場合:- このリソース・スコープはaliveではありません
- このリソース・スコープは制限されており、このメソッドは、このリソース・スコープを所有するスレッド以外のスレッドから呼び出されます
- このリソース・スコープは共有され、このメソッドを呼び出したときにこのスコープに関連付けられたリソースにアクセス
- このリソース・スコープの「依存」がクローズされていない1つ以上のスコープ。
UnsupportedOperationException
- このリソース・スコープが「グローバル・スコープ」の場合。
-
addCloseAction
void addCloseAction(Runnable runnable) リソース・スコープがクローズされたときに実行されるカスタム・クリーンアップ・アクションを追加します。 スコープがクローズされると、カスタム・クリーンアップ・アクションが起動される順序は指定されません。- パラメータ:
runnable
- このスコープに関連付けられるカスタム・クリーンアップ・アクション。- 例外:
IllegalStateException
- このスコープが閉じられている場合、またはこのスコープを所有するスレッド以外のスレッドからアクセスが発生した場合。
-
keepAlive
void keepAlive(ResourceScope target) このスコープとターゲット・スコープの間に一時的な依存関係を作成します。 その結果、このスコープの前にターゲット・スコープをclosedにすることはできません。- 実装上のノート:
- 特定のスコープでは、保留中のキープアライブ・リクエストを最大
Integer.MAX_VALUE
でサポートできます。 - パラメータ:
target
- 存続する必要がある範囲。- 例外:
IllegalArgumentException
-target == this
の場合。IllegalStateException
- このスコープまたはtarget
が閉じられている場合、またはこのスコープまたはtarget
を所有するスレッド以外のスレッドからアクセスが発生した場合。
-
newConfinedScope
static ResourceScope newConfinedScope()新しい限定スコープを作成します。- 戻り値:
- 新しい限定スコープ。
-
newConfinedScope
static ResourceScope newConfinedScope(Cleaner cleaner) 提供されたクリーナ・インスタンスによって管理される、新しい限定されたスコープを作成します。- パラメータ:
cleaner
- 返されたスコープに関連付けられるクリーナ。- 戻り値:
cleaner
によって管理される新しい限定スコープ。
-
newImplicitScope
static ResourceScope newImplicitScope()プライベートCleaner
インスタンスによって管理される新しい共有スコープを作成します。 (ただし、より効率的である可能性があります。)と同等のコードは次のとおりです:newSharedScope(Cleaner.create());
- 戻り値:
- プライベート
Cleaner
インスタンスによって管理される共有スコープ。
-
globalScope
static ResourceScope globalScope()「グローバル・スコープ」を返します。- 戻り値:
- 「グローバル・スコープ」。
-