アプリケーションでメモリ リークの問題が発生しました。次の簡単な例で問題の 1 つを再現することができました。
レプリケーションのセットアップ
1) オブジェクトの作成/破棄を追跡するために使用される次のヘルパー クラスを作成します。
public class TestObject
{
public static int Count { get; set; }
public TestObject()
{
Count++;
}
~TestObject()
{
Count--;
}
}
2) 3 つのボタンを持つ MDI フォームを作成します。最初のボタンは、次のように新しい MDI 子を作成します。
private void ctlOpenMDI_Click(object sender, EventArgs e)
{
Form newForm = new Form();
newForm.MdiParent = this;
newForm.Tag = new TestObject();
newForm.Show();
}
2 番目のボタンを使用して同じことを行いますが、非 MDI 子フォームを使用します。
private void ctlOpenNonMDIForm_Click(object sender, EventArgs e)
{
Form newForm = new Form();
newForm.Tag = new TestObject();
newForm.Show();
}
3 番目のボタンはガベージ コレクションに使用され、ライブの TestObject インスタンスの数が表示されます。
private void ctlCount_Click(object sender, EventArgs e)
{
GC.Collect();
GC.WaitForPendingFinalizers();
MessageBox.Show("Count: " + TestObject.Count);
}
レプリケーションの手順
1) [MDI フォームを開く] ボタンをクリックし、MDI フォームを閉じてから、[カウント] ボタンをクリックします。Count: 1 が返されます。MDI 子フォームとそれが参照するオブジェクトは、ガベージ コレクションされませんでした。何かがまだそれへの参照を持っている必要があります。
また:
[MDI フォームを開く] を 3 回クリックし、3 つのフォームをすべて閉じてから、カウント ボタンをクリックします。Count: 1 が返されます。最後に閉じられた MDI 子フォームがガベージ コレクションされていないようです。
カウンターケース:
1) [非 MDI フォームを開く] をクリックして閉じます。次に、カウントボタンをクリックします。Count: 0 を返します。フォームとオブジェクトはガベージ コレクションされています。
回避策
これを行うことで、この問題を回避できます。
Form form = new Form();
form.MdiParent = this;
form.Show();
form.Close();
ガベージコレクションの前。これにより、このダミー フォームが最後に閉じられた MDI 子フォームになり、他のフォームをガベージ コレクションできるようになりますが、なぜこれを行う必要があるのでしょうか。何が起こっている?
また、フォームの開閉でちらつきが発生するため、少し見苦しく、かなりハッキーに見えます。