GC not finalizing UserControl?
本文关键字:UserControl finalizing not GC | 更新日期: 2023-09-27 18:20:07
我有一个CF应用程序,它会随着时间的推移泄漏UserControls。这花了一些时间,但我缩小了范围,甚至在整个框架中复制了行为(3.5)。由于这两种行为都存在,我不想称之为bug,但我确实不明白为什么会发生这种情况,希望有人能对此有所了解。
因此,我创建了一个简单的WinForms应用程序,其中包含一个Form和一个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。它只是跟踪活动(即未最终确定)实例的数量。它上面什么都没有,只有一个标签,所以我可以直观地确认它在表格上。
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());
}
}
奇怪的是,实例数无限增长。最终,在设备上,我的内存用完了。我怀疑我也会在电脑上,我只是不想点击明年的按钮。
现在,如果我像这样更改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的名义这是默认行为?
那么,为什么会发生这种情况呢?很明显,基地正在调用SuppressFinalize,但这到底是为什么会发生,为什么以Odin的名义这是默认行为?
这是(正确地)实现IDisposable
的类的默认行为。当您调用IDisposable.Dispose
时,默认情况下,建议的行为是禁止终结,因为终结的主要原因是清理从未被释放的资源。这是因为完成是一项昂贵的操作——您不希望不必要地完成对象,并且如果调用了Dispose
,则认为您已经清理了非托管资源。任何托管内存都将被处理。
您应该覆盖Dispose
,并在Dispose
覆盖范围内递减。
IDisposable
的文档中解释了这种行为。示例Dispose
方法调用实现是(来自参考文档):
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time
GC.SuppressFinalize(this);
}