Version: Unity 6.0 (6000.0)
言語 : 日本語
スレッドセーフタイプ
NativeContainer 構造体のコピー

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

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

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

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

使用状況の実装

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

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

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

リーク追跡の実装

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

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

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

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

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

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

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

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

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

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

追加リソース

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