Когда я должен использовать GC.SuppressFinalize ()? - PullRequest
260 голосов
/ 30 сентября 2008

В .NET, при каких обстоятельствах я должен использовать GC.SuppressFinalize()?

Какие преимущества дает мне этот метод?

Ответы [ 5 ]

278 голосов
/ 30 сентября 2008

SuppressFinalize должен вызываться только классом, имеющим финализатор. Он сообщает сборщику мусора (GC), что объект this полностью очищен.

Рекомендуемый шаблон IDisposable при наличии финализатора:

public class MyClass : IDisposable
{
    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // called via myClass.Dispose(). 
                // OK to use any private object references
            }
            // Release unmanaged resources.
            // Set large fields to null.                
            disposed = true;
        }
    }

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

    ~MyClass() // the finalizer
    {
        Dispose(false);
    }
}

Обычно CLR сохраняет вкладки на объектах с помощью финализатора, когда они создаются (что делает их создание более дорогим). SuppressFinalize сообщает GC, что объект был очищен правильно, и ему не нужно идти в очередь финализатора. Он выглядит как деструктор C ++, но не действует так, как он.

Оптимизация SuppressFinalize не тривиальна, поскольку ваши объекты могут долго жить в очереди финализатора. Не поддавайтесь искушению вызвать SuppressFinalize для других объектов. Это серьезный дефект, который должен произойти.

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

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

Примечание. Иногда кодеры добавляют финализатор для отладки сборок своих собственных классов IDisposable, чтобы проверить, что код правильно расположил их объект IDisposable.

    public void Dispose() // Implement IDisposable
    {
        Dispose(true);
    #if DEBUG
        GC.SuppressFinalize(this);
    #endif
    }

    #if DEBUG
    ~MyClass() // the finalizer
    {
        Dispose(false);
    }
    #endif
35 голосов
/ 30 сентября 2008

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

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

Как правило, любой метод Dispose () может вызывать GC.SupressFinalize (), поскольку он должен очищать все, что будет очищено в финализаторе.

SupressFinalize - это просто то, что обеспечивает оптимизацию, которая позволяет системе не беспокоить очередь объекта в поток финализатора. Правильно написанный Dispose () / финализатор должен работать должным образом с или без вызова GC.SupressFinalize ().

2 голосов
/ 30 сентября 2008

Этот метод должен вызываться для метода Dispose объектов, который реализует IDisposable, таким образом, GC не будет вызывать финализатор в другой раз, если кто-то вызовет метод Dispose.

См .: http://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize.aspx

1 голос
/ 16 апреля 2018
 Dispose(true);
 GC.SuppressFinalize(this);

Если объект имеет финализатор, .net помещает ссылку в очередь финализации

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

Поэтому вызовите GC.SuppressFinalize (this), чтобы удалить ссылку в очереди завершения.

0 голосов
/ 27 апреля 2018

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

Стоимость GC.KeepAlive() и GC.SuppressFinalize(this) практически одинакова в любом классе, в котором нет финализатора, а классы, в которых есть финализаторы, обычно должны вызывать GC.SuppressFinalize(this), поэтому использование последней функции в качестве последнего шага из Dispose() не всегда может быть необходимо, но это не будет неправильно.

...