Finalize vs Dispose

Почему некоторые люди используют Finalize способ по Dispose способ?

в каких ситуациях вы бы использовать Finalize способ по Dispose метод и наоборот?

13 ответов


другие уже покрыли разницу между Dispose и Finalize (кстати,Finalize метод по-прежнему называется деструктором в спецификации языка), поэтому я просто добавлю немного о сценариях, где Finalize способ пригодится.

некоторые типы инкапсулируют располагаемые ресурсы таким образом, что их легко использовать и утилизировать одним действием. Общее использование часто таково: открыть, прочитать или написать, закрыть (Dispose). Это очень хорошо вписывается в using строительство.

другие немного сложнее. WaitEventHandles для экземпляров не используются так, как они используются для передачи сигнала из одного потока в другой. Тогда возникает вопрос, кто должен позвонить Dispose на эти? В качестве защитных типов, подобных этим, реализуют Finalize метод, который гарантирует, что ресурсы будут удалены, когда экземпляр больше не ссылается на приложение.


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

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

стандартный практика заключается в реализации IDisposable и Dispose чтобы вы могли использовать свой объект в using statment. Такие как using(var foo = new MyObject()) { }. И в вашем финализаторе вы называете Dispose, на всякий случай, если вызывающий код забыл избавиться от вас.


Finalize-это метод backstop, вызываемый сборщиком мусора при восстановлении объекта. Dispose-это метод "детерминированной очистки", вызываемый приложениями для освобождения ценных собственных ресурсов (дескрипторов окон, подключений к базе данных и т. д.) когда они больше не нужны, а не оставляют их на неопределенный срок, пока GC не доберется до объекта.

как пользователь объекта, вы всегда используете Dispose. Финализация для GC.

в качестве исполнителя класса, если вы держите управляемые ресурсы, которые должны быть удалены, вы реализуете Dispose. Если у вас есть собственные ресурсы, вы реализуете Dispose и Finalize и вызываете общий метод, который освобождает собственные ресурсы. Эти идиомы обычно объединяются через частный метод Dispose (bool disposing), который Dispose вызовы с true и Finalize вызовы с false. Этот метод всегда освобождает собственные ресурсы, а затем проверяет параметр disposing и, если это правда, удаляет управляемые ресурсы и вызовы GC.SuppressFinalize.


завершить

  • финализаторы всегда должны быть protected, а не public или private Так что метод может быть вызван из кода приложения непосредственно и в то же время, он может сделать вызов base.Finalize метод
  • финализаторы должны выпускать только неуправляемые ресурсы.
  • платформа не гарантирует, что финализатор будет выполняться вообще на любом данном экземпляре.
  • не выделять память в завершители или вызов виртуальных методов из завершителей.
  • избегайте синхронизации и создания необработанных исключений в финализаторах.
  • порядок выполнения финализаторов недетерминирован-другими словами, вы не можете полагаться на другой объект, все еще доступный в вашем финализаторе.
  • не определяйте завершители для типов значений.
  • не создавайте пустые деструкторы. Другими словами, вы никогда не должны явно определять деструктор, если ваш класс должен очистить неуправляемые ресурсы, и если вы определяете один, он должен выполнить некоторую работу. Если позже вам больше не нужно очищать неуправляемые ресурсы в деструкторе, удалите его полностью.

Dispose

  • реализовать IDisposable на каждом типе, который имеет финализатор
  • убедитесь, что объект стал непригодным для использования после вызова Dispose метод. Другими словами, избегайте использования объекта после Dispose способ был призван на это.
  • вызов Dispose на все IDisposable типы, как только вы закончите с ними
  • разрешить Dispose вызывается несколько раз без возникновения ошибок.
  • подавить более поздние вызовы финализатора из Dispose способ использования GC.SuppressFinalize метод
  • избегайте создания одноразовых типов значений
  • избежать исключений из Dispose методы

Dispose / Finalized Шаблон

  • корпорация Майкрософт рекомендует использовать как Dispose и Finalize при работе с неуправляемыми ресурсами. The Finalize реализация будет запущена, и ресурсы все равно будут освобождены, когда объект будет собирать мусор, даже если разработчик забыл вызвать Dispose явного метода.
  • очистка неуправляемых ресурсов в Finalize и Dispose метод. Дополнительно вызовите Dispose метод для любых объектов .NET, которые у вас есть как компоненты внутри этого класса (имеющие неуправляемые ресурсы в качестве их члена) из Dispose метод.

Finalize вызывается GC, когда этот объект больше не используется.

Dispose - это обычный метод, который пользователь этого класса может вызвать для освобождения любых ресурсов.

Если пользователь забыл вызвать Dispose и если класс Finalize реализован, то GC удостоверится, что он будет вызван.


есть несколько ключей из книги MCSD Certification Toolkit (exam 70-483) pag 193:

деструктор ≈(он почти равен) база.Finalize (), деструктор преобразуется в переопределенную версию метода Finalize, который выполняет код деструктора, а затем вызывает метод Finalize базового класса. Тогда его полностью не детерминированный вы не можете знать, когда будет вызван, потому что зависит от GC.

если класс не содержит ни управляемые ресурсы и неуправляемые ресурсы, это не нужно реализовать IDisposableor есть деструктор.

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

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

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

метод Dispose должен освободить как управляемые, так и неуправляемые ресурсы.

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

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

пример реализации класса с неуправляемыми и управляемыми ресурсами:

using System;

class DisposableClass : IDisposable
{
    // A name to keep track of the object.
    public string Name = "";

    // Free managed and unmanaged resources.
    public void Dispose()
    {

        FreeResources(true);
    }

    // Destructor to clean up unmanaged resources
    // but not managed resources.
    ~DisposableClass()
    {
        FreeResources(false);
    }

    // Keep track if whether resources are already freed.
    private bool ResourcesAreFreed = false;

    // Free resources.
    private void FreeResources(bool freeManagedResources)
    {
        Console.WriteLine(Name + ": FreeResources");
        if (!ResourcesAreFreed)
        {
            // Dispose of managed resources if appropriate.
            if (freeManagedResources)
            {
                // Dispose of managed resources here.
                Console.WriteLine(Name + ": Dispose of managed resources");
            }

            // Dispose of unmanaged resources here.
            Console.WriteLine(Name + ": Dispose of unmanaged resources");

            // Remember that we have disposed of resources.
            ResourcesAreFreed = true;

            // We don't need the destructor because
            // our resources are already freed.
            GC.SuppressFinalize(this);
        }
    }
}

99% времени, вы не должны беспокоиться о любого. :) Но если ваши объекты содержат ссылки на неуправляемые ресурсы (например, дескрипторы окон, дескрипторы файлов), вам необходимо предоставить способ для управляемого объекта освободить эти ресурсы. Finalize дает неявный контроль над высвобождением ресурсов. Он называется сборщиком мусора. Dispose-это способ дать явный контроль над выпуском ресурсов и может быть вызван напрямую.

существует гораздо больше узнать о предмете Вывоз Мусора, но это только начало.


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

правильно реализовать финализатор, как известно, трудно и следует избегать, где это возможно -SafeHandle класс (avaialble в .Net v2.0 и выше) теперь означает, что вам очень редко (если когда-либо) нужно реализовать финализатор.

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

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

посмотреть обновление DG: утилизация, завершение и ресурс Управление для того, что я считаю лучшим и наиболее полным набором рекомендаций по финализаторам и IDisposable.


лучший пример, который я знаю.

 public abstract class DisposableType: IDisposable
  {
    bool disposed = false;

    ~DisposableType()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(false);
      }
    }

    public void Dispose()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(true);
        GC.SuppressFinalize(this);
      }
    }

    public void Close()
    {
      Dispose();
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposing) 
      {
        // managed objects
      }
      // unmanaged objects and resources
    }
  }

разница между методами Finalize и Dispose в C#.

GC вызывает метод finalize для восстановления неуправляемых ресурсов (таких как file operarion, Windows api, сетевое подключение, подключение к базе данных), но время, когда GC будет вызывать его, не установлено. Он называется неявно GC это означает, что у нас нет контроля низкого уровня на нем.

Dispose метод: у нас есть контроль низкого уровня на нем, как мы называем его из кода. мы можем вернуть неуправляемые ресурсы, как только почувствуем это. бесполезно.Мы можем достичь этого, реализовав IDisposal pattern.


экземпляры классов часто инкапсулируют контроль над ресурсами, которые не управляются средой выполнения, такими как дескрипторы окон (HWND), подключения к базе данных и т. д. Поэтому вы должны предоставить как явный, так и неявный способ освобождения этих ресурсов. Обеспечить неявное управление путем реализации защищенного метода Finalize на объекте (синтаксис деструктора в C# и управляемые расширения для C++). Сборщик мусора вызывает этот метод в какой-то момент после того, как там не действует ссылки на объект. В некоторых случаях может потребоваться предоставить программистам, использующим объект, возможность явного освобождения этих внешних ресурсов до освобождения объекта сборщиком мусора. Если внешний ресурс является дефицитным или дорогостоящим, то можно повысить производительность, если программист явно высвобождает ресурсы, когда они больше не используются. Чтобы обеспечить явный контроль, реализуйте метод Dispose, предоставляемый интерфейсом IDisposable. Потребитель объекта должны вызвать этот метод, когда это делается с помощью объекта. Dispose можно вызвать, даже если другие ссылки на объект живы.

обратите внимание, что даже если вы предоставляете явный контроль с помощью Dispose, вы должны предоставить неявную очистку с помощью метода Finalize. Finalize предоставляет резервную копию для предотвращения постоянной утечки ресурсов, если программист не может вызвать Dispose.


резюме -

  • вы пишете финализатор для своего класса, если он имеет ссылку на неуправляемый ресурсы и вы хотите убедиться, что эти неуправляемые ресурсы освобождаются, когда экземпляр этого класса является собранным мусором автоматически. Обратите внимание, что вы не можете вызвать финализатор объекта явно - он вызывается автоматически сборщиком мусора по мере необходимости.
  • С другой стороны, вы реализуете IDisposable интерфейс и следовательно, определите метод Dispose () как результат для вашего класса), когда ваш класс есть ссылки на неуправляемые ресурсы, но вы не хотите ждать сборщик мусора на удар (который может быть в любое время - не в управление программистом) и хотите освободить эти ресурсы как как только закончишь. Таким образом, вы можете явно освободите неуправляемые ресурсы, вызвав метод Dispose() объекта.

кроме того, еще одно отличие - в Метод Dispose() реализации, вы также должны освободить управляемые ресурсы, тогда как это не должно быть сделано в Финализаторе. Это потому, что очень вероятно, что управляемые ресурсы, на которые ссылается объект, уже были очищены до того, как он будет готов к завершению.

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

class ClassWithDisposeAndFinalize : IDisposable
{
    // Used to determine if Dispose() has already been called, so that the finalizer
    // knows if it needs to clean up unmanaged resources.
     private bool disposed = false;

     public void Dispose()
     {
       // Call our shared helper method.
       // Specifying "true" signifies that the object user triggered the cleanup.
          CleanUp(true);

       // Now suppress finalization to make sure that the Finalize method 
       // doesn't attempt to clean up unmanaged resources.
          GC.SuppressFinalize(this);
     }
     private void CleanUp(bool disposing)
     {
        // Be sure we have not already been disposed!
        if (!this.disposed)
        {
             // If disposing equals true i.e. if disposed explicitly, dispose all 
             // managed resources.
            if (disposing)
            {
             // Dispose managed resources.
            }
             // Clean up unmanaged resources here.
        }
        disposed = true;
      }

      // the below is called the destructor or Finalizer
     ~ClassWithDisposeAndFinalize()
     {
        // Call our shared helper method.
        // Specifying "false" signifies that the GC triggered the cleanup.
        CleanUp(false);
     }

Как мы знаем, dispose и finalize используются для освобождения неуправляемых ресурсов.. но разница в том, что finalize использует два цикла для освобождения ресурсов, где as dispose использует один цикл..