Когда избавиться от метода не будет вызван? - PullRequest
7 голосов
/ 10 сентября 2009

Я читал эту статью на днях и задавался вопросом, почему был финализатор наряду с методом Dispose. Я прочитал здесь , чтобы узнать, почему вы можете добавить Dispose в Finalizer. Мне любопытно, когда Finalizer будет вызываться поверх самого метода Dispose? Существует ли пример кода или он основан на том, что происходит в системе, в которой работает программное обеспечение? Если это так, то может случиться, что метод Dispose не будет запущен GC.

Ответы [ 5 ]

10 голосов
/ 10 сентября 2009

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

В связи с этим важно располагать объект немного иначе, чем при работе с финализатором.

~MyClass()
{
    Dispose(false);
}

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected void Dispose(disposing)
{
    if (!this.disposed)
    {
        if (disposing)
        {
            // Dispose managed resources here.
        }
        // Dispose unmanaged resources here.
    }
    this.disposed = true;
}

Причина, по которой вы не не хотите распоряжаться управляемыми ресурсами в своем финализаторе, заключается в том, что вы на самом деле будете создавать сильные ссылки на них при этом, и это может помешать GC правильно выполнить свою работу и собрать их. Конечно, неуправляемые ресурсы (например, дескрипторы Win32 и т. Д.) Всегда должны быть явно закрыты / удалены, поскольку CLR о них ничего не знает.

4 голосов
/ 10 сентября 2009

Это в основном там, чтобы защитить себя. Вы не можете диктовать, что будет делать конечный пользователь вашего класса. Предоставляя финализатор в дополнение к методу Dispose, GC «удалит» ваш объект, освободив ваши ресурсы соответствующим образом, даже если пользователь забудет вызвать Dispose () или неправильно использует ваш класс.

2 голосов
/ 10 сентября 2009

Финализатор вызывается, когда объект собирается мусором. Утилизация должна быть явно вызвана. В следующем коде будет вызван финализатор, но нет метода Dispose.

class Foo : IDisposable
{
  public void Dispose()
  {
    Console.WriteLine("Disposed");
  }

  ~Foo()
  {
    Console.WriteLine("Finalized");
  }
}

...

public void Go()
{
  Foo foo = new Foo();
}
1 голос
/ 10 сентября 2009

Метод dispose должен быть явно вызван либо вызовом Dispose (), либо наличием объекта в операторе using. GC всегда вызывает финализатор, поэтому, если что-то должно произойти до того, как объекты будут удалены из финализатора, следует по крайней мере проверить, чтобы убедиться, что все в объекте очищено.

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

0 голосов
/ 11 марта 2011

Важное, но тонкое замечание, еще не упомянутое: редко рассматриваемая цель утилизации состоит в том, чтобы предотвратить преждевременную очистку объекта. Объекты с финализаторами должны быть написаны тщательно, чтобы финализатор не запустился раньше , чем ожидалось. Финализатор не может быть запущен до начала последнего вызова метода, который будет сделан для объекта (*), но иногда он может запускать во время последнего вызова метода, если объект будет отменен после того, как метод завершается. Код, который правильно удаляет объект, не может покинуть объект перед вызовом Dispose, поэтому нет опасности, что финализатор нанесет ущерб коду, который правильно использует Dispose. С другой стороны, если последний метод, использующий объект, использует сущности, которые будут очищены в финализаторе после последнего использования самой ссылки на объект, сборщик мусора может вызвать Finalize для объекта и очистить до объектов, которые все еще используются. Решение заключается в том, чтобы гарантировать, что любой метод вызова, использующий сущности, которые будут очищены финализатором, должен в какой-то момент сопровождаться вызовом метода, который использует «this». GC.KeepAlive (это) хороший метод для этого.

(*) Невиртуальные методы, которые расширены до встроенного кода, который ничего не делает с объектом, могут быть освобождены от этого правила, но Dispose обычно является или вызывает виртуальный метод.

...