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

> Implement custom native containers.

カスタムのネイティブコンテナを実装するには、型に [`NativeContainer`](/engine/6000.0/script-reference/unity-collections-low-level-unsafe/native-container-attribute.md) 属性の注釈を付ける必要があります。また、ネイティブコンテナが [安全システム](/engine/6000.0/manual/scripting/optimization/job-system/native-container.md#safety-system) にどのように統合されるかを理解する必要があります。

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

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

## 使用状況の実装

コードでの使用状況の追跡には [`AtomicSafetyHandle`](/engine/6000.0/script-reference/unity-collections-low-level-unsafe/atomic-safety-handle.md) クラスを使用します。`AtomicSafetyHandle` は、安全システムが特定のネイティブコンテナのために保存する中心的な情報への参照を保持し、`NativeContainer` のメソッドが安全システムと相互作用する主な方法です。このため、すべての `NativeContainer` インスタンスに `m_Safety` という名前の `AtomicSafetyHandle` フィールドが必要です。

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

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

## リーク追跡の実装

Unity のネイティブコードはもともとリーク追跡を実装しています。[`UnsafeUtility.MallocTracked`](/engine/6000.0/script-reference/unity-collections-low-level-unsafe/unsafe-utility/malloc-tracked.md) メソッドを使用して `NativeContainer` データの保存に必要なメモリを割り当て、[`UnsafeUtility.FreeTracked`](/engine/6000.0/script-reference/unity-collections-low-level-unsafe/unsafe-utility/free-tracked.md) を使用してデータを破棄します。

以前のバージョンの Unity では、[`DisposeSentinel`](/engine/6000.0/script-reference/unity-collections-low-level-unsafe/dispose-sentinel.md) クラスがリーク追跡機能を提供します。Unity は、[ガベージコレクター](/engine/6000.0/manual/analysis/performance-memory-overview/managed-memory/garbage-collector.md) が `DisposeSentinel` オブジェクトを収集するとメモリリークを報告します。`DisposeSentinel` を作成するには `Create` メソッドを使用します。このメソッドは同時に `AtomicSafetyHandle` を初期化します。このメソッドを使用する場合、`AtomicSafetyHandle` を初期化する必要はありません。`NativeContainer` が破棄されると、`Dispose` メソッドは 1 回の呼び出しで `DisposeSentinel` と `AtomicSafetyHandle` の両方を破棄します。

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

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

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

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

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

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

名前を登録するには、[`NewStaticSafetyId`](/engine/6000.0/script-reference/unity-collections-low-level-unsafe/atomic-safety-handle/new-static-safety-id.md) を使用します。これは [`SetStaticSafetyId`](ScriptRef:Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.SetStaticSafetyIdl) に渡すことができるセーフティ ID を返します。セーフティ ID を作成したら、`NativeContainer` のすべてのインスタンスで再利用できます。そのため、コンテナクラスの静的メンバーに格納するのが一般的です。

特定の安全制約違反のエラー メッセージを [`SetCustomErrorMessage`](/engine/6000.0/script-reference/unity-collections-low-level-unsafe/atomic-safety-handle/set-custom-error-message.md) でオーバーライドすることもできます。

## 追加リソース

* [NativeContainer 構造体のコピー](/engine/6000.0/manual/scripting/optimization/job-system/native-container/copy-nativecontainer.md)
* [カスタム NativeContainer の例](/engine/6000.0/manual/scripting/optimization/job-system/native-container/custom-nativecontainer-example.md)
