ガベージ コレクションのテストを作成していて、デバッグ モードで発生する一連の奇妙なバグに遭遇しました。これは、抽出された POC コードです。20 個のラムダのリストと、それらへの弱参照のリストがあります。13 番目のラムダにアクセスし (.ToString() を呼び出して)、リストをクリアします。次に、ガベージ コレクションを強制し、クリーンアップで残った要素を分析します。
public void TestGC_WTF() {
var handlers = new List<Action>();
var weakReferences = new List<WeakReference>();
int testValue = 0;
for (int i = 0; i < 20; i++) {
int number = i;
Action handler = () => testValue += number;
handlers.Add(handler);
weakReferences.Add(new WeakReference(handler));
handler = null;
}
handlers[13].ToString();
handlers.Clear();
GC.Collect();
if (false) { } //This is required for the bug to occur.
var aliveReferences = Enumerable.Range(0, weakReferences.Count).Where(i => weakReferences[i].IsAlive).ToArray();
Console.WriteLine("Uncollected handlers: {0}", string.Join(",", aliveReferences));
}
デバッグ モードでは、このコードは ("Uncollected handlers: 13,19") を出力します。この結果で発生する問題は次のとおりです。
- 19 番目の要素は収集されません (各ループ反復の最後にハンドル変数を明示的に null に設定しても)
- 13番目の要素は収集されません(どこにも保存していませんが)
if (false) { }
(またはその他のループ/条件) は、バグをトリガーするために不可欠です。
問題の原因は何ですか?(デバッグでは、オブジェクトが定義されているブロックの最後まで保持されることを知っています。これだけでは、私が抱えている問題はまだ説明されていません。)
Microsoft にバグを提出しましたが、問題の原因にもっと興味がありますhttps://connect.microsoft.com/VisualStudio/feedback/details/775082/strangely-triggered-strange-bugs-with-garbage -デバッグビルドのコレクション