Unity / C# 値型、参照型、スタック、ヒープ、ガベージコレクションGC(理論)

目次

1. 値型と参照型の概念

値の種類 (値):

参照タイプ (参照):

参照型はヒープ上にあり、値型はスタック上にありますか?

2. 値型と参照型の違いは何ですか

3. では、ヒープとスタックとは何でしょうか? 

スタック

ヒープ

4. ガベージコレクター (GC)


免責事項: このコンテンツはさまざまな資料や個人的な要約に基づいています。

1. 値型と参照型の概念

値の種類 (値):

int float bool 構造 列挙(enum)など。

参照タイプ (参照):

要素が値型であってもクラス配列は参照(int[]は参照) デリゲート(delegate)は参照 インターフェイス(interface)は参照だが値で実装可能種類など

参照型はヒープ上にあり、値型はスタック上にありますか?

  1. 常にヒープ上にある型のインスタンスを参照することに問題はありませんが、メソッド内で宣言された変数とメソッド パラメーターはスタック上にあります。また、インスタンス変数の値は、常にインスタンス自体が保存されている場所に保存されます。たとえば、クラス内に int 変数がある場合、それは値型ではありますが、ヒープ上にあります。
  2. 参照型の変数には、変数に直接関連付けられた記憶場所と、変数に格納された値によって参照される記憶場所の 2 つの記憶場所が含まれます。
  3. 変数に直接関連付けられた格納場所と値型変数に関連付けられた格納場所では、格納場所に違いはなく、参照自体は値型と同じになります。しばらくすると、スタックの一時ストレージ プールに割り当てられます。

2. 値型と参照型の違いは何ですか

  1. 代入後、2 つの値が同期的に変化するかどうか、値の型が割り当てられるかどうか、およびそれらが独立しているかどうかの違いです。代入後は参照型が1つになり、一方が変わるともう一方も変わります。 

3. では、ヒープとスタックとは何でしょうか? 

  • スタック

スタックはメモリ内に予約された特別なスペースで、小規模で短期間のデータ値を格納するために特別に使用されます。データ値が関数を超えると自動的に解放されるため、スタックと呼ばれます。データ構造のスタックと同様に、メモリ スタックにもプッシュとポップがあります。
宣言されたすべてのローカル変数 (int a; など) はスタックに配置され、関数が呼び出されたときにそれらのロードとアンロードが処理されます。つまり、変数はプログラムの実行前にスタック上に定義されています。これらの関数呼び出しは、いわゆるコール スタックを通じて展開および縮小されます。現在の関数のコール スタックの処理が完了すると、コール スタックの前のコール ポイントに戻り、終了した位置から残りのコンテンツの実行が続行されます。前。以前のメモリ割り当ての場所は常にわかっており、新しいメモリ割り当てによって古いデータが上書きされるため、メモリ クリーンアップ操作を実行する必要がないため、スタックは比較的効率的です。
スタックの合計サイズは通常、メガバイト (MB) 程度と小さくなります。スタックがサポートできる以上のスペースを割り当てると、スタック オーバーフローが発生する可能性があります。スタック オーバーフローは、多数の呼び出しスタック (無限ループなど) を実行するとき、または多数のローカル変数があるときに発生しますが、ほとんどの場合、スタックのサイズが比較的小さいにもかかわらず、スタック オーバーフローが発生することはほとんどありません。

  • ヒープ

ヒープは他のすべてのメモリ空間を表し、ほとんどのメモリ割り当てに使用されます**。ほとんどのメモリ割り当ては現在の関数呼び出しよりも長く保持する必要があるため、スタックに割り当てることはできません。これは、メソッドの実行終了の前後に生成された結果がスタックによって上書きされるためです。データ型が大きすぎる場合や、関数の外に保持する必要がある場合があるため、ヒープが存在します。ヒープとスタックの間に物理的な違いはなく、どちらも RAM に存在するデータ バイトを含む単なるメモリ空間です。オペレーティング システムは、これらのデータ バイトを要求して保存します。違いは、いつ、どこで、どのように使用されるかです。
C++ で書かれた言語などのネイティブ コードでは、これらのメモリ割り当ては手動で処理され、すべてのメモリ ブロックが正しく割り当てられていることを確認し、不要な場合は明示的にメモリを解放するのが私たちの責任です。そうしないと、メモリが不足してプログラムがクラッシュするまで、メモリ リークが発生しやすくなります。
マネージド言語では、メモリ解放はガベージ コレクターによって自動的に処理されます。Unity プログラムの初期化中に、Mono プラットフォームはオペレーティング システムからメモリの文字列を適用して、使用するヒープ メモリ空間 (通常はマネージド ヒープと呼ばれます) を生成します。 C#コードで。このヒープ領域は、最初は 1MB 未満と比較的小さいですが、スクリプト コードが新しいメモリ チャンクを必要とするにつれて増加します。Unity がそれを必要としなくなった場合は、そのスペースを OS に解放して戻すことで縮小できます。

4. ガベージコレクター (GC)

ガベージ コレクター (GC) には、必要以上に管理されたメモリが使用されないようにする重要な仕事があり、不要になったメモリは自動的に再利用されます。つまり、GC はオブジェクトの作成と破棄に参加します。例: GameObject を作成してそれを破棄すると、GC はオブジェクトによって使用されているメモリ空間にマークを付け、後でこのメモリを再利用できるようにします。メモリの回復はリアルタイムではなく、メモリが必要でない場合にのみ回復されることに注意してください。

Unity で使用される Mono のバージョンの GC は、マーク アンド スイープ戦略を使用するトレース GC です。アルゴリズムは 2 つのフェーズに分かれています。

割り当てられた各オブジェクトは、追加のデータ ビットによって追跡されます。このデータ ビットは、オブジェクトがマークされているかどうかを示します。これらのフラグは false に設定され、フラグが設定されていないことを示します。収集プロセスが開始されると、オブジェクトのフラグ Alive を true に設定することにより、プログラムからまだアクセス可能なすべてのオブジェクトにマークが付けられます。アクセス可能なオブジェクトは、直接参照 (スタック上の静的変数またはローカル変数など)、または他の直接または間接的にアクセス可能なオブジェクトのフィールド (メンバー変数) を介した間接参照のいずれかです。理論的には、参照されていないオブジェクトはすべてリサイクルされる必要があります。
2 番目のフェーズでは、そのような参照 (GC はプログラムの存続期間全体にわたって追跡します) を反復処理し、そのマーキング状態に基づいてリサイクルする必要があるかどうかを決定します。オブジェクトがマークされていない場合、そのオブジェクトは収集の候補とみなされます。このフェーズでは、マークされたオブジェクトは直接スキップされますが、次のガベージ コレクション スキャンの前にそれらのオブジェクトが false にリセットされ、新しいラウンドのマークが完了します。
第 2 ステージの実行が終了すると、マークされていないすべてのオブジェクトが正式に再利用されてスペースが解放され、オブジェクト作成のアクシデント リクエストが再検討されます。GC が十分なスペースを解放した場合は、新しく解放されたスペースにメモリを割り当てて、電話をかけてきた人。解放されたスペースが十分でない場合は、システムから追加のマネージド ヒープを申請することしかできません。

実際、GC はすべてのオブジェクトのリストをメモリ内に保持しますが、アプリケーションはオブジェクトの一部のみを含む別のリストを保持します。プログラムはオブジェクトの処理が完了すると、そのオブジェクトをリサイクルする必要があるかどうかに関係なく、ただちにその存在を忘れてリストから削除します。言い換えれば、ガベージ コレクションの作業は GC によって独立して実行され、プログラムは独自のオブジェクト リストを維持するだけで済みます。

ゲームには高いパフォーマンスが要求されるため、効率を向上させるために、シーンの切り替え時やリソースが頻繁に使用されないときに GC を呼び出すことができます。

おすすめ

転載: blog.csdn.net/q1295006114/article/details/130915670