У меня есть приложение CF, которое со временем течет UserControls. Это заняло некоторое время, но я сузил его и даже воспроизвел поведение в полной структуре (3.5). Поскольку поведение существует в обоих случаях, я не хочу называть его ошибкой, но я уверен, что не понимаю, почему это происходит, и надеюсь, что кто-то может пролить свет на него.GC не завершает работу с UserControl?
Поэтому я создаю простое приложение WinForms с формой и кнопкой. Нажатие на кнопку чередуется между созданием нового UserControl и Disposing этого элемента управления. Очень просто.
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());
}
}
Странная вещь здесь заключается в том, что количество экземпляров растет бесконечно. В конце концов, на устройстве у меня заканчивается память. Я подозреваю, что я тоже на ПК, я просто не склонен нажимать кнопку на следующий год.
Теперь, если я изменить по умолчанию, конструктор сгенерированный Dispose метод в UserControl как это, просто добавив вызов ReRegisterForFinalize:
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
if (disposing)
{
GC.ReRegisterForFinalize(this);
}
}
Затем он ведет себя точно так, как и ожидалось, Доработка экземпляров во время сбора (при ручной или автоматический) ,
Так почему же это происходит? Очевидно, что база вызывает SuppressFinalize, но почему именно это происходит, и почему во имя Одина это поведение по умолчанию?
+1 на самом деле имея реальную причину для рассмотрения с помощью GC, – Sayse
Учитывая, Риду (жаль не может помочь на фактическом решении!) ответ, что делает финализатор в вашем реальном коде? Не мог ли вызвать финализатор вызвать утечку? – svick
Реальный код вообще не имеет финализаторов. У них есть Dispose, и Bitmaps и т.п. удаляются. – ctacke