Почему мой деструктор никогда не бежит? - PullRequest
12 голосов
/ 03 августа 2011

У меня есть пустой Winform с методом деструктора

public partial class Form1 : Form
{
    public Form1()
    {
        System.Diagnostics.Trace.WriteLine("Form1.Initialize " + this.GetHashCode().ToString());
        InitializeComponent();
    }
    ~Form1()
    {
        System.Diagnostics.Trace.WriteLine("Form1.Dispose " + this.GetHashCode().ToString());
    }
}

Когда форма уничтожена, я хочу, чтобы она записала в окно вывода:

(Form1 opened)
Form1.Initialize 41149443
(Form1 closed)
<b>Form1.Dispose 41149443</b>

MSDN предлагает 3 способав реализации деструктора:

Однако ни один из этих способов не записывает «Form1. Dispose 41149443» в окно вывода.Поэтому я не могу сказать, была ли форма уничтожена или нет.Предложения?Должен ли я отказаться от надежды на достижение этого из-за неопределенности сборщика мусора?Есть ли другой способ узнать, был ли Form1 собран мусором?

Ответы [ 6 ]

9 голосов
/ 03 августа 2011

Только один из трех способов реализации деструктора, который вы перечисляете, на самом деле включает деструктор, и это ~Destructor().

Если вы реализуете IDisposable и утилизируете свой объект, то код в Dispose будет работать, но нет никаких оснований полагать, что ваш деструктор будет работать.

Я думаю, что вы гонитесь за невозможным здесь. Деструкторы запускаются как и когда сборщик мусора так велит. Это не то, что вы можете контролировать. GC вполне может сформировать мнение о том, что бегущие деструкторы просто тратят время, и, если у них достаточно памяти, они формируют это мнение.

Если вам нужно предсказуемое удаление, завершение и т. Д., Используйте IDisposable.

4 голосов
/ 03 августа 2011

Если вы не изучаете сборку мусора, деструктор не место для вашей трассировки. Вы должны посмотреть на Dispose (который можно переопределить в форме). Это происходит после освобождения неуправляемого ресурса (например, вашего дескриптора окна).

protected override void Dispose(bool disposing)
{
   System.Diagnostics.Trace.WriteLine(
      "Form1.Dispose " + (disposing ? "disposing " : "")
      + this.GetHashCode().ToString());
   base.Dispose (disposing);
}

Если вы хотите узнать, была ли удалена форма / элемент управления, используйте свойство Control.IsDisposed.

Edit: из-за GC.SuppressFinalize ваш метод Finalize (синтаксис деструктора в C #) никогда не будет выполняться, если Dispose вызывается явно (или из-за фреймворка).

Для получения дополнительной информации см. Реализация метода удаления .

1 голос
/ 03 апреля 2014

Добавить событие FormClosed для дизайнера.

т.е.:

this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(Form1_FormClosed);

Затем создайте соответствующую функцию для обработки события.

1 голос
/ 03 августа 2011

Форма получает сборщик мусора, когда нет ссылок, и сборщик мусора запускается. Вы можете принудительно запустить сборщик мусора, вызвав GC.Collect (). Вы не должны ссылаться на любой другой объект в Finalizer (он же деструктор), потому что объект, возможно, уже был собран мусором.

Вы можете использовать инструменты анализатора памяти, чтобы выяснить, является ли ваш объект сборщиком мусора или нет, если вам это действительно нужно.

Вы также должны иметь в виду, что финализатор вызывается из потока, отличного от основного потока.

EDIT: Если ваша проблема заключается только в том, что вы не видите вывод трассировки, вам может потребоваться включить автозапуск на

<configuration>
  <system.diagnostics>
    <trace autoflush="true" />
  </system.diagnostics>
</configuration>

РЕДАКТИРОВАТЬ 2: Там может быть внешняя ссылка на вашу форму, например, зарегистрированный обработчик событий. Я бы посоветовал вам добавить кнопку в области администрирования вашего приложения, которая выполняет следующий код:

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

Таким образом, сборщик мусора должен работать и должен уничтожить вашу форму (установите точку останова в финализаторе). Если нет, у вас есть ссылка на объект, который должен быть уничтожен.

1 голос
/ 03 августа 2011

Да, вы, вероятно, должны отказаться от идеи деструктора, потому что они недетерминированы по своей природе. Я не уверен, почему вам нужно иметь форму disposed в отличие от только что закрытой, но в большинстве случаев достаточно просто закрыть ее.

Вы можете использовать IDisposable, но это зависит от того, зачем вам нужна форма для сбора мусора. Если вам нужно использовать его повторно, просто создайте другой экземпляр.

0 голосов
/ 03 августа 2011

Вы можете попробовать обернуть вашу форму в объект WeakReference, а затем проверить его свойство IsAlive, чтобы определить, был ли он собран мусором.Но да ... в соответствии с другими ответами вам может быть лучше оставить его и доверить ГХ свою работу!

...