Вопрос

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

Это было полезно?

Решение

Целью финализатора здесь является просто мера безопасности от утечек памяти (если вы не вызываете 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 о них не знает.

Другие советы

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

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

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

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

...

public void Go()
{
  Foo foo = new Foo();
}

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top