Unity の マネージメモリーシステム は、Mono または IL2CPP 仮想マシン (VM) をベースにした C# スクリプト環境です。マネージメモリシステムの利点は、メモリの解放を管理してくれることです。そのため、コードを通してメモリの解放を手動でリクエストする必要はありません。
Unity のマネージメモリシステムは、スクリプトが割り当てられたメモリへの参照を維持しなくなると、ガベージコレクター と マネージヒープ を使用して、自動的にメモリ割り当てを解放します。これにより、メモリリークを防止することができます。メモリリークは、メモリが割り当てられ、その参照が失われ、その後、そのメモリが解放されない場合に発生します。なぜなら、そのメモリを解放するには、そのメモリへの 参照 が必要だからです。
このメモリ管理システムは、メモリアクセスも監視します。つまり、解放されたメモリや、コードがアクセスするために有効ではなかったメモリにはアクセスできないということです。ただし、マネージメモリの割り当ては CPU にとって時間がかかるため、このメモリ管理プロセスはランタイムのパフォーマンスに影響を与えます。また、ガベージコレクション が終了するまで、CPU は他の作業をしない場合もあります。
メソッドが呼び出されると、スクリプトバックエンドはそのパラメータの値を、コールスタック と呼ばれるデータ構造内のその特定の呼び出しのために予約されたメモリ領域にコピーします。スクリプトバックエンドは、数バイトのデータタイプを素早くコピーできます。しかし、オブジェクト、文字列、配列などのデータはずっと大きくなることが多く、スクリプトバックエンドがこれらの型のデータを定期的にコピーするのは非効率です。
マネージコード内のすべての null ではない 参照型オブジェクト とすべての ボックス化された値型オブジェクト は、マネージヒープ上に割り当てられなければなりません。
値型と参照型に精通していることは重要です。そうすれば、コードを効果的に管理することができます。詳細については、Microsoft のドキュメント 値型 、参照型 を参照してください。
オブジェクトが作成されると、Unity はそのオブジェクトを格納するのに必要なメモリを ヒープ と呼ばれる主要プールから割り当てます。ヒープは、Unity プロジェクトで選択されたスクリプトランタイム(Mono または IL2CPP) が自動的に管理するメモリのセクションです。オブジェクトが使用されなくなると、そのオブジェクトが使用していたメモリは再利用され、別の用途に使用されます。
Unity のスクリプトバックエンド は、ガベージコレクタ を使用して、アプリケーションのメモリを自動的に管理します。そのため、明示的なメソッド呼び出しでメモリブロックを割り当てたり解放したりする必要がなくなります。自動メモリ管理は、明示的な割り当て/解放よりもコーディングの手間が少なく、メモリリークの可能性も低減します。
マネージヒープ は、Unity プロジェクトで選択されたスクリプトランタイム (Mono または IL2CPP) が自動的に管理するメモリのセクションです。
上の図で、青いボックスはマネージヒープに割り当てられたメモリ量を示しています。中にある白いボックスが、マネージヒープのメモリ領域内に格納されたデータの値を示しています。追加のデータ値が必要になると、マネージヒープの使用されていない領域が割り当てられます。
上の図は、メモリの断片化の例です。Unity がオブジェクトを解放すると、オブジェクトが占有していたメモリは解放されます。しかし、その空きスペースは、1 つの大きな “開放されたメモリ ” プールの一部にはなりません。
解放されたオブジェクトに隣り合うオブジェクトは、まだ使用されている可能性があります。このため、解放されたスペースは、メモリの他のセグメントの間の “ギャップ” になります。このギャップは、解放されたオブジェクトと同じかそれ以下のサイズのデータを格納することにしか利用できません。
このような状況を メモリの断片化 と呼びます。これは、ヒープに大量のメモリがあるにもかかわらず、オブジェクトとオブジェクトの間の “ギャップ” でしか利用できない場合に起こります。つまり、大きなメモリ割り当てのために十分な総容量があるにもかかわらず、マネージヒープには、それを割り当てられるのに十分な大きさの、ひとまとまりの連続したメモリブロックが見つからないのです。
上の図のように、大きなオブジェクトが割り当てられ、それを格納するためのひとまとまりの空き領域が不足している場合、Unity のメモリマネージャは 2 つの処理を行います。
ヒープの予期せぬ拡大は問題となる可能性があります。Unity のガベージコレクションによる方法は、より頻繁にメモリを断片化する傾向があります。以下の点に注意する必要があります。
GC.Collect
to make sure the state of these references is up to date. Bear in mind that:
UnloadUnusedAssets
is not triggered automatically, only manually and on scene changes. If you want to free that memory earlier, which can be crucial, for example, for fullscreen RenderTextures on platforms with low RAM, you should call Destroy on the objects to make optimal use of the memory you have.UnloadUnusedAssets
or GC.Collect
triggers a CPU-intensive process that you might want to avoid during Gameplay.