Подтвердить что ты не робот

Какова цель GC.SuppressFinalize(this) в методе Dispose()?

У меня есть код, который выглядит так:

/// <summary>
/// Dispose of the instance
/// </summary>
public void Dispose()
{
    if (_instance != null)
    {
        _instance = null;
        // Call GC.SupressFinalize to take this object off the finalization
        //  queue and prevent finalization code for this object from
        //  executing a second time.
        GC.SuppressFinalize(this);
    }
}

Хотя есть комментарий, который объясняет назначение этого вызова, связанного с GC, я до сих пор не понимаю, почему он там.

Не объект, предназначенный для сбора мусора, когда все экземпляры перестают существовать (например, при использовании в блоке using())?

Какой сценарий использования, где это будет играть важную роль?

Спасибо!

4b9b3361

Ответ 1

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

Чтобы запретить запуск метода dispose дважды (в случае, если объект уже был удален), вы добавляете GC.SuppressFinalize(this);. В документации приведен пример :

class MyResource : IDisposable
{
    [...]

    // This destructor will run only if the Dispose method 
    // does not get called.
    ~MyResource()      
    {
        // Do not re-create Dispose clean-up code here.
        // Calling Dispose(false) is optimal in terms of
        // readability and maintainability.
        Dispose(false);
    }

    // Implement IDisposable.
    // Do not make this method virtual.
    // A derived class should not be able to override this method.
    public void Dispose()
    {
        Dispose(true);
        // This object will be cleaned up by the Dispose method.
        // Therefore, you should call GC.SupressFinalize to
        // take this object off the finalization queue 
        // and prevent finalization code for this object
        // from executing a second time.
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called.
        if(!this.disposed)
        {
            // If disposing equals true, dispose all managed 
            // and unmanaged resources.
            if(disposing)
            {
                // Dispose managed resources.
                component.Dispose();
            }

            // Call the appropriate methods to clean up 
            // unmanaged resources here.
            resource.Cleanup()          
        }
        disposed = true;         
    }
}

Ответ 2

Сбор мусора: GC восстанавливает память, используемую объектом, когда объект ссылается не более.

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

Finalizer: метод освобождения всех неуправляемых ресурсов. Вызывается GC перед восстановлением памяти.

Управляемый ресурс: любой .NET-класс, который реализует интерфейс IDisposable, например Streams и DbConnections.

Неуправляемый ресурс: начинка, завернутая в классы управляемого ресурса. Ручки Windows - это тривиальные примеры.


Теперь, чтобы ответить на ваш вопрос:

GC хранит список (очередь завершения) всех объектов, класс которых объявляет Finalizer (~ ClassName в С#). Объекты помещаются в эту очередь при создании. GC периодически запускается, чтобы проверить, отсутствуют ли какие-либо объекты, недоступные из программы. Затем он проверяет, ссылаются ли какие-либо из недоступных объектов из очереди завершения, и помещает их в другую очередь, называемую очередью Freachable, а остальные возвращаются. Отдельный поток используется для запуска методов Finalize объектов в очереди Freachable.

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

Метод SuppressFinalize просто устанавливает флаг в заголовок объекта, который указывает, что Finalizer не нужно запускать. Таким образом, GC может сразу вернуть память объекта. В соответствии с вышеприведенным определением метод Dispose выполняет то же самое, что и Finalizer (и многое другое), поэтому, если он выполняется, то завершение не требуется. Используя метод SuppressFinalize, вы можете сохранить некоторую работу для GC, уведомив об этом факте. Кроме того, теперь вам не нужно выполнять проверки в Finalizer, чтобы избежать двойного освобождения. Единственная проблема с Dispose заключается в том, что не гарантируется выполнение, потому что это ответственность программиста за это, поэтому нам иногда приходится беспокоиться о Finalizers.


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


Дальнейшее чтение:

Ответ 3

Объекты, которые могут быть завершены, выживают при первом запуске GC.

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

Это означает, что конечный объект несет дополнительную стоимость: объект должен храниться в памяти в течение более длительного времени. Следовательно, вы видите: вы должны прекратить финализацию, когда она не нужна. Здесь объект использует финализацию, чтобы гарантировать, что он всегда "удаляется" в какой-то момент. Когда он явно размещен, его больше не нужно дорабатывать.

Ответ 4

Если ваш тип реализует финализатор (~MyType() { }), он не позволяет сборщику мусора запускать его. Используется, когда ваш финализатор заботится о неуправляемых типах, но пользователь уже вызвал Dispose() (либо явно, либо через блок using() { }), освободив эти неуправляемые типы.

Ответ 5

Из MSDN: GC.SuppressFinalize:

Этот метод устанавливает бит в объекте заголовок, который система проверяет, когда вызывающие финализаторы. Параметр obj должен быть вызывающим Метод.

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

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