変数スコープの最後までオブジェクトは生きているという誤解

先日に引き続き,@IT 会議室突っ込みシリーズ.

未記入さんの書き込み (2008-10-01 21:41) より:

バグではない理由:
参照していると、回収されません。Dispose は、メモリの破棄ではありません。

参照しているというのは fm2 のことでしょうか。fm2 はループ内で宣言されているので、ループ 1周ごとにスコープを抜ける、つまり new Form2() は参照されていない状態になるのではないでしょうか?

GC.Collect() で直前の fm2 が解放されるとは思っていませんが、ループ 1周遅れで、ひとつまえの new Form2() インスタンスは GC で回収されても良さそうに思います。直近の 1インスタンスは GC.Collect() で回収されないと思いますが、それだけでメモリ使用量が増加傾向になるものでしょうか?

よねKENさんのフォローと同じだと思いますが。

オリジナルのコード

while (true) 
{ 
    Form2 fm2 = new Form2(); 
    fm2.ShowDialog(); 
    fm2.Dispose(); 
    GC.Collect(); 
}

GC.Collect が実行されるときには fm2 は参照されています。従って、1つは残ります。

1 つ必ず残るとは限りません.Compact CLR の特定バージョンがそういう実装になっているといった話なら分かりますが,CLI 仕様からは「1 つ必ず残る」と断定はできないはずです.
(C# では) 変数スコープの最後までオブジェクトは生きているというこの誤解,あちこちで目にしますが,実際にはそんなことは保証されていません.C# コンパイラは,スコープ終了点までオブジェクトを延命するようなコードを必要もなく埋め込みません.その結果,デスクトップ CLR では比較的簡単に「スコープ終了前の回収」を見ることができます.特徴的なケースでは,生成したオブジェクトのコンストラクタが完了する前に,そのオブジェクトが回収されることすらあります*1
詳しくは『 プログラミングMicrosoft .NET Framework 第2版』の第 20 章あたりをどうぞ.

プログラミングMicrosoft .NET Framework 第2版 (マイクロソフト公式解説書)

プログラミングMicrosoft .NET Framework 第2版 (マイクロソフト公式解説書)