都内で働くSEの技術的なひとりごと / Technical soliloquy of System Engineer working in Tokyo

都内でサラリーマンやってます。SQL Server を中心とした (2023年からは Azure も。) マイクロソフト系(たまに、OSS系などマイクロソフト以外の技術も...)の技術的なことについて書いています。日々の仕事の中で、気になったことを技術要素関係なく気まぐれに選んでいるので記事内容は開発言語、インフラ等ばらばらです。なお、当ブログで発信、発言は私個人のものであり、所属する組織、企業、団体等とは何のかかわりもございません。ブログの内容もきちんと検証して使用してください。英語の勉強のため、英語の

GC.Collect() は使い過ぎに注意です!と思って記事かいてみた

今回やることを説明してみる

 メモリを早いとこ回収させたいがために、GC.Collect() を乱用してしまう人がたまにいるので、簡単なサンプルを交えて説明します。あー、こーゆーことが発生するんだなぁと思っていただければいいと思います。

使用する環境を説明してみる

 Visual Studio 2013 Update2 を使用します。

サンプルソースを試してみる

 早速下記のソースを実行してみましょう。WindowsFormアプリケーションで Button クリックイベントあたりに実装したらよいかと思います。

private void button1_Click(object sender, EventArgs e)
{
    var d = new Dictionary<string, object>();

    //最初はもちろんGen0です。
    MessageBox.Show("Generation:" + GC.GetGeneration(d).ToString() + ",object:" + d.ToString());

    GC.Collect();

    //GC.Collect()で回収対象にならなかったため、Gen1に移動する。
    MessageBox.Show("Generation:" + GC.GetGeneration(d).ToString() + ",object:" + d.ToString());

    GC.Collect();

    //GC.Collect()で回収対象にならなかったため、Gen2に移動する。
    MessageBox.Show("Generation:" + GC.GetGeneration(d).ToString() + ",object:" + d.ToString());

    var o = new GCTest();
    d.Add("test", o);

    //Gen2 から Gen0 の参照が発生する。
    MessageBox.Show("Generation:" + GC.GetGeneration(o).ToString() + ",object:" + o.ToString());
}

 実行すると、インスタンス化した Dictionary の世代が 0 → 1 → 2 と上がっていくのがわかるかと思います。そして、世代 0 の GCTest のインスタンスが 世代 2 の Dictionary に追加されます。これにより、早期に解放されるべき世代 0 の GCTest のインスタンスが、解放されないという事態に陥ってしまいます。

おわりに何かいってみる

 .NET って難しいなぁ。わからないことだらけです。そもそもこの記事の内容があっているのか、誰か検証してほしいくらいです。
※ガーベージコレクションの本。

ガベージコレクションのアルゴリズムと実装

ガベージコレクションのアルゴリズムと実装