Какова цель GC.SuppressFinalize (это) в Располагает () метод?

У меня есть следующий код:

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 блок?

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

29
задан Community 29 May 2018 в 03:13
поделиться

5 ответов

При реализации шаблона удаления вы также можете добавить в свой класс финализатор, который вызывает 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;         
    }
}
34
ответ дан 28 November 2019 в 01:03
поделиться

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

2
ответ дан 28 November 2019 в 01:03
поделиться

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

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

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

6
ответ дан 28 November 2019 в 01:03
поделиться

Из MSDN: GC.SuppressFinalize :

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

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

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

0
ответ дан 28 November 2019 в 01:03
поделиться

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

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

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

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

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


Теперь ответим на ваш вопрос:

GC хранит список (Finalization Queue) всех объектов, класс которых объявляет Finalizer (~ClassName в C#). Объекты помещаются в эту очередь при создании. GC периодически запускается, чтобы проверить, есть ли объекты, недоступные из программы. Затем он проверяет, ссылаются ли на какие-либо из недоступных объектов из очереди финализации, и помещает их в другую очередь, называемую очередью Freacheable, в то время как остальные объекты освобождаются. Для выполнения методов Finalize объектов в очереди Freacheable используется отдельный поток.

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

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


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


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

32
ответ дан 28 November 2019 в 01:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: