Version: 2023.1
言語: 日本語
スレッドセーフタイプ
NativeContainer 構造体のコピー

カスタムネイティブコンテナの実装

カスタムのネイティブコンテナを実装するには、型に NativeContainer 属性のアノテーションをを付ける必要があります。また、ネイティブコンテナが 安全システム とどのように統合されるかを理解する必要があります。

実装するには、大きく分けて 2 つの要素があります。

  • 使用状況の追跡: Unityが NativeContainer インスタンスを使用するスケジュールされたジョブを追跡できるようにします。これにより、2 つのジョブが同時に同じネイティブコンテナに書き込むなどの潜在的な競合を検出して防ぐことができます。
  • リークの追跡: NativeContainer が適切に廃棄されなかったケースを検出します。この場合、メモリリークが発生し、NativeContainer に割り当てられたメモリがプログラムの残りの生存期間全体にわたって使用できなくなります。

使用状況の実装

コード内で使用状況状況にアクセスするには AtomicSafetyHandle クラスを使用します。AtomicSafetyHandle は、安全システムが特定のネイティブコンテナのために保存する中心的な情報への参照を保持し、NativeContainer のメソッドが安全システムと相互作用する主な方法です。このため、すべての NativeContainer インスタンスにはm_Safety という AtomicSafetyHandle フィールドが必要です。

AtomicSafetyHandle は、現在のコンテキストでネイティブコンテナに対して実行できる操作の種類を示す一揃いのフラグを保存しています。ジョブに NativeContainer インスタンスが含まれる場合、ジョブシステムは自動的に AtomicSafetyHandle 内のフラグを構成し、そのジョブでネイティブコンテナを使用できる方法を反映します。

ジョブが NativeContainer インスタンスから読み取ろうとすると、ジョブシステムは読み取る前に CheckReadAndThrow メソッドを呼び出し、ジョブがネイティブコンテナへの読み取りアクセス権を持っていることを確認します。同様に、ジョブがネイティブコンテナに書き込もうとすると、ジョブシステムは書き込む前に CheckWriteAndThrow を呼び出し、ジョブがネイティブコンテナへの書き込みアクセス権を持っていることを確認します。同じ NativeContainer インスタンスを割り当てられた 2 つのジョブは、そのネイティブコンテナの AtomicSafetyHandle オブジェクトを別々に持ちます。そのため、2 つのジョブは同じ中央情報を参照しますが、各ジョブがネイティブコンテナに対してどのような読み取りと書き込みのアクセス権を持っているかを示す、それぞれ別のフラグを持つことができます。

リーク追跡の実装

Unity のネイティブコードは主にリーク追跡を実装しています。これは UnsafeUtility.MallocTracked メソッドを使用し、NativeContainer のデータを格納するのに必要なメモリを割り当て、 UnsafeUtility.FreeTracked を使用して破棄します。

Unity の以前のバージョンでは ディスポーズセンチネルDisposeSentinel](../ScriptReference/Unity.Collections.LowLevel.Unsafe.DisposeSentinel.html) クラスがリーク追跡を提供します。ガベージコレクターDisposeSentinel オブジェクトを収集すると、Unity はメモリリークを報告します。DisposeSentinel を作成するには、Create メソッドを使用し、同時に AtomicSafetyHandle を初期化します。このメソッドを使用する場合、AtomicSafetyHandle を初期化する必要はありません。NativeContainer が破棄されると、Dispose メソッドは DisposeSentinelAtomicSafetyHandle の両方を 1 回の呼び出しで破棄します。

リークした NativeContainer がどこで作成されたかを特定するには、メモリが最初に割り当て られた場所のスタックトレースをキャプチャします。そのためには NativeLeakDetection.Mode プロパティを使用します。このプロパティにはエディターでもアクセスできます。これを行うには、Preferences > Jobs > Leak Detection Level と移動して、必要なリーク検出レベルを選択します。

ネストされたネイティブコンテナ

安全システムはジョブ内のネストされたネイティブコンテナをサポートしていません。ジョブシステムは、より大きな NativeContainer インスタンス内の個々の NativeContainer に対して AtomicSafetyHandle を正しく設定できないためです。

ネストされたネイティブコンテナを使用するジョブをスケジュールしないようにするには、SetNestedContainer を使用します。これは、NativeContainer が他の NativeContainer インスタンスを含む場合に、ネスト状態であるというフラグを立てる機能です。

セーフティ ID とエラーメッセージ

安全システムは、コードが安全制約を守っていないことを示すエラーメッ セージを提供します。エラーメッセージをわかりやすくするために、NativeContainerオブジェクトの名前を安全システムに登録できます。

名前を登録するには NewStaticSafetyId を使用します。これは、SetStaticSafetyId に渡すことができるセーフティ ID を返します。セーフティ ID を作成すると、NativeContainer のすべてのインスタンスで再利用できます。一般的なパターンでは、コンテナクラスの静的メンバーに格納されます。

また、特定の安全制約違反に対するエラーメッセージをオーバーライドすることもできます。 SetCustomErrorMessage.

その他の参考資料

スレッドセーフタイプ
NativeContainer 構造体のコピー