5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

今更C#におけるメモリ管理の勉強をする

Last updated at Posted at 2023-04-20

始めに

今までC#におけるメモリ管理のことを意識しないままUnityでの開発を行ってきたのですが、就活をするにあたりこのままではよくないなと思って馴染みのあるC#のメモリ管理について再度勉強をすることにした。

今回はこちらの資料を参考にさせていただきました↓

https://ufcpp.net/study/computer/MemoryManagement.html?key=stack#stack

【スタック】

積み上げるという言葉通りデータ領域を積み上げていく形で管理する方式

最後に確保した領域を最初に開放する。

【ヒープ】

任意サイズのデータ領域を、任意の順序で確保/解放する方式。(スタックが整然と積み上げていくイメージなのに対して、ヒープは乱雑に山積みされているイメージ)

ヒープは以下のような場合に利用する。

  • データを必要とするスコープ(データの利用範囲)がはっきりしない場合
    • 例:データがさまざまな箇所から参照されている場合
  • 実行時にしかサイズが確定しない場合
    • 例:利用者からの入力に応じてサイズを変える必要がある場合
  • 必要サイズがかなり大規模な場合

ローカル変数はスタック上に値を置く。

それが「値型」の場合、値すべてがスタック上に置かれる。

一方、「参照型」の場合、実際の値はヒープ上に置かれ、そのヒープ上の場所への参照情報(「ポインター」 )だけがスタック上に置かれる。

【ヒープの管理方法】

ヒープを利用するときにメモリリーク(用済みのデータ領域を解放しないでそのままにしておくこと)や二重解放(すでに解放済みの領域を再度解放しようとすること)と呼ばれる問題を起こしてしまうことがある。そんな大変なヒープの管理を自動化してくれる手法の内の1つがガベージ・コレクション。

【ガベージ・コレクション】

定期的に用済みのデータがないかを調べて、あった場合には解放をしてくれる。

(ガベージ・コレクションにはいくつか方式があるがここでは扱わない。別記事でいつかまとめたい)

C#はガベージコレクションを使える言語なのでメモリ管理は基本的にはガベージ・コレクションに任せた方が手動よりも高性能。

が、ガベージ・コレクションを利用すると処理が走ったタイミングで負荷が1点集中するため重くなることがあるうえに、ガベージ・コレクションはいつ処理が走るかわからない。そのため、急にガベージ・コレクションが走り、一時的に性能が落ちることがある。

そこで、

ガベージ・コレクションを明示的に行う方法ってないのかな…

って思って調べてみたらちゃんとあった。

以下ガベージ・コレクションを明示的に行う方法

https://learn.microsoft.com/ja-jp/dotnet/api/system.gc.collect?view=net-7.0

じゃあ

ガベージ・コレクションを強制的に走らせない方法はないのかな…

って思って調べたら以下のドキュメントを発見した。

https://docs.unity3d.com/ja/2020.3/Manual/performance-disabling-garbage-collection.html

ドキュメントからの引用になるが、

ガベージコレクションを無効にするのはアプリケーションの中でも短い時間、パフォーマンスが重要な部分だけで、必要なメモリの割り当て量を計算して制御することができる場合にすべきです。その後、すぐにガベージコレクションを有効にし、プロジェクトを頻繁にプロファイルして、マネージヒープが大きくなりすぎる原因となる追加のマネージアロケーション (割り当て) が発生しないようにする必要があります。

とある通り、ガベージ・コレクションを無効にするタイミングはかなり慎重に選ばないといけないし、その後の処理もしっかりとケアしてあげないといけない。

明示的に無効、有効にすることはできるが適切な処理を加えないとまずいよって話なのでほんとに特になにも問題がない場合はガベージ・コレクションを明示的にいじる必要はない。

そんなガベージ・コレクションにも限界はある。

ガベージ・コレクションが「このデータはもういらないから解放しよう」って判定するのはあくまでも「有効な領域から参照されていないデータ」なので必要がないのに参照し続けると判定されずに解放されない。

例えば、寿命の長い(ずっと使い続けている)メモリ領域から、寿命の短いメモリ領域を参照している場合、本来ならすぐに解放していいはずの寿命の短いメモリ領域が寿命の長い領域に合わせていつまでも解放されないで残ってしまう。

最後に

Unity、C#を学び始めたころからもっとちゃんとここら辺の勉強をしておけばよかったなと後悔していますがそんなこと言っても仕方がないので今からでも勉強していきます。

読んでくださりありがとうございました。
引き続き頑張ります。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?