6

時間の経過とともに UserControls がリークする CF アプリケーションがあります。少し時間がかかりましたが、絞り込み、完全なフレームワーク (3.5) で動作を再現しました。動作は両方に存在するため、バグとは言いたくありませんが、なぜそれが起こっているのか理解できず、誰かがそれに光を当ててくれることを願っています.

そこで、フォームとボタンを使用して単純な WinForms アプリを作成します。Button をクリックすると、新しい UserControl の作成とそのコントロールの破棄が交互に行われます。とてもシンプルです。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    UserControl1 m_ctl;

    private void button1_Click(object sender, EventArgs e)
    {
        if (m_ctl == null)
        {
            m_ctl = new UserControl1();
            m_ctl.Visible = true;
            this.Controls.Add(m_ctl);
        }
        else
        {
            this.Controls.Remove(m_ctl);
            m_ctl.Dispose();
            m_ctl = null;
            GC.Collect();
        }
    }
}

そして、これが UserControl です。ライブ (つまり、ファイナライズされていない) インスタンスの数を追跡するだけです。ラベルが 1 つしかないので、フォーム上にあることを視覚的に確認できます。

public partial class UserControl1 : UserControl
{
    private static int m_instanceCount = 0;

    public UserControl1()
    {
        var c = Interlocked.Increment(ref m_instanceCount);
        Debug.WriteLine("Instances: " + c.ToString());

        InitializeComponent();
    }

    ~UserControl1()
    {
        var c = Interlocked.Decrement(ref m_instanceCount);
        Debug.WriteLine("Instances: " + c.ToString());
    }
}

ここで奇妙なのは、インスタンス数が無期限に増加することです。最終的に、デバイスでメモリが不足します。私は PC でもそうすると思いますが、来年のボタンをクリックする気はありません。

ここで、デザイナーが生成した UserControl のデフォルトの Dispose メソッドを次のように変更すると、ReRegisterForFinalize 呼び出しを追加するだけです。

protected override void Dispose(bool disposing)
{
    if (disposing && (components != null))
    {
        components.Dispose();
    }

    base.Dispose(disposing);

    if (disposing)
    {
        GC.ReRegisterForFinalize(this);
    }
}

その後、期待どおりに動作し、収集中にインスタンスをファイナライズします (手動または自動の場合)。

では、なぜこれが起こっているのですか?ベースが SuppressFinalize を呼び出していることは明らかですが、正確にはなぜこれが起こっているのでしょうか。Odin の名の下に、なぜそれがデフォルトの動作なのですか?

4

1 に答える 1