時間の経過とともに 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 の名の下に、なぜそれがデフォルトの動作なのですか?