Почему традиционный шаблон Dispose подавляет финализацию? - PullRequest
9 голосов
/ 20 декабря 2010

Предполагая, что это традиционный шаблон Dispose (взят из devx, но встречается на многих сайтах)

class Test : IDisposable
{
  private bool isDisposed = false;

  ~Test()
  {
    Dispose(false);
  }

  protected void Dispose(bool disposing)
  {
    if (disposing)
    {
      // Code to dispose the managed resources of the class
    }

    // Code to dispose the un-managed resources of the class

    isDisposed = true;
  }

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

Я не понимаю, почему мы называем GC.SupressFinalize(this).Это требует от меня написания собственного распоряжения ресурсами, включая обнуление моих ссылок?Я немного растерялся, должен признать.Может ли кто-нибудь пролить свет на этот шаблон?

В идеале я хотел бы распоряжаться только своими неуправляемыми ресурсами и позволить GC самостоятельно осуществлять управляемый сбор.

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

Ответы [ 6 ]

14 голосов
/ 20 декабря 2010

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

Финализатор существует только какОткат в случае, если клиентский код не может вызвать Dispose по какой-либо причине.

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

И, если ваш собственный класс использует только управляемые ресурсы, тогда финализатор совершенно не нужен:GC позаботится о любых управляемых ресурсах, и пусть сами эти ресурсы будут беспокоиться о том, нужен ли им запасной финализатор.Вы должны рассматривать финализатор только в своем классе, если он непосредственно обрабатывает неуправляемые ресурсы.

3 голосов
/ 20 декабря 2010

SuppressFinalize только подавляет любой пользовательский финализатор.

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

Нет разницы между классом без финализатора и экземпляром, для которого вы вызвали SuppressFinalize.

Вызов SuppressFinalize предотвращаетдополнительный вызов Dispose(false), и делает GC несколько быстрее.(финализаторы дорогие)

Обратите внимание, что классы без неуправляемых ресурсов не должны иметь финализатор.(Они все равно должны вызывать SuppressFinalize, если они не запечатаны; это позволяет унаследованным классам добавлять неуправляемые ресурсы)

2 голосов
/ 03 апреля 2012

от MSDN: » Этот метод устанавливает бит в заголовке объекта, который система проверяет при вызове финализаторов. Параметр obj должен быть вызывающим для этого метода. Объекты, которые реализуют интерфейс IDisposable, могут вызывать этот метод из метода IDisposable.Dispose, чтобы сборщик мусора не вызывал Object.Finalize для объекта, который ему не требуется. «

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

2 голосов
/ 20 декабря 2010

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

Чтобы понять, почему это важно, вы должны думать о финализации не как о части сборки мусора, а о том, что происходит перед ней. Когда класс регистрируется для завершения (автоматически при создании, если он переопределяет Finalize), он помещается в специальный список, называемый Очередь завершения. Ни один объект в очереди завершения, ни какой-либо объект, на который прямо или косвенно ссылается объект в очереди, не могут быть удалены мусором , но если обнаруживается, что какой-либо объект в очереди завершения не имеет корневых ссылок кроме очереди , объект будет извлечен из очереди и запустится финализатор. Во время отправки финализатора объект не будет доступен для сбора (поскольку во время отправки будет существовать ссылка); после завершения работы финализатора ссылки на объект, как правило, больше не будут, поэтому он (и объекты, на которые он ссылается) обычно будет собираемым.

Лично я считаю SuppressFinalize глупым, поскольку я не могу придумать ни одной веской причины, по которой производный класс должен иметь финализатор. Если производный класс собирается добавить свои неуправляемые ресурсы (*), о которых родительский класс ничего не будет знать, следует создать другой класс для хранения этих ресурсов; родительский класс должен содержать ссылку на это. Таким образом, сам родительский класс не будет нуждаться в финализации, и объекты, на которые ссылается родительский класс, не будут излишне заблокированы от сборки мусора.

1 голос
/ 20 декабря 2010

Как отмечено в MSDN , выполнение метода Finalize является дорогостоящим. Вызывая dispose, вы уже самостоятельно завершили свой класс, поэтому не нужно вызывать финализатор. Финализатор реализуется в случае, если Dispose никогда не вызывается напрямую вашим кодом (или тем, кто «владеет» экземпляром).

0 голосов
/ 28 февраля 2018
// If the monitor.Dispose method is not called, the example displays the following output:
//       ConsoleMonitor instance....
//       The ConsoleMonitor class constructor.
//       The Write method.
//       The ConsoleMonitor finalizer.
//       The Dispose(False) method.
//       Disposing of unmanaged resources.
//       
// If the monitor.Dispose method is called, the example displays the following output:
//       ConsoleMonitor instance....
//       The ConsoleMonitor class constructor.
//       The Write method.
//       The Dispose method.
//       The Dispose(True) method.
//       Disposing of managed resources.
//       Disposing of unmanaged resources.

С https://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize(v=vs.110).aspx

...