В чем разница между ресурсами, расположенными в финализаторе, и ресурсами, освобожденными в утилизации - PullRequest
0 голосов
/ 22 января 2019

Это дополнительный вопрос к этому вопросу:

Завершение / удаление шаблона в C #

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

protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }   
        // get rid of unmanaged resources
    } 

Так в чем же разница между утилизацией финализатора и утилизацией метода утилизации?

Ответы [ 4 ]

0 голосов
/ 22 января 2019

GC вызовы ~finalizer до объекта будут собраны.

Это означает, что управляемые члены объекта будут или уже собраны (я не знаю таких нюансов о том, как работает GC).

Таким образом, уже нет необходимости очищать управляемых участников, и обычно в ~finalizer есть Dispose(false), чтобы предотвратить это.

~B()
{
    Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        // get rid of managed resources
    }   
    // get rid of unmanaged resources
}

Когда мы удаляем объект вручную, вызывая метод Dispose() или используя using, члены объекта должны быть очищены и подготовлены к сбору (установите значения в null и т. Д.). Итак, у нас есть Dispose(true) в Dispose() методе и GC.SuppressFinalize(this); для отключения вызова ~finalizer, потому что нет необходимости после того, как члены объекта уже очищены и не вызывать Dispose(bool disposing) дважды.

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}
0 голосов
/ 22 января 2019

В дополнение к данному ответу: финализатор вызывается сборщиком мусора при запуске.

Так что вы не можете рассчитывать на время освобождения неуправляемых ресурсов в финализаторе!Потому что он неизвестен.

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

Итак, сначала сборщик мусора вызывает finalezrs, но объект не собирается (а также объекты, на которые ссылается объект), он будет собран во второй сборке мусора.

0 голосов
/ 22 января 2019

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

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

Как правило, использование финализаторов может быть очень сложным и сложным, если ваше приложение должно выдерживать критические исключения, такие как нехватка памяти или прерывание потока и последующие выгрузки AppDomain - это касается таких приложений, как SQL Server или IIS.

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

Вы можете найти больше чтения по этой теме в следующих сообщениях в блоге:

Эрик Липперт - Когда все, что вы знаете, неверно

Джо Даффи - Никогда больше не пиши финализатор

0 голосов
/ 22 января 2019

Единственная причина, по которой вы будете его использовать (и это крайне противоречиво).

  1. Финализатор позволяет очистить объект перед его удалением сборщиком мусора.(То есть, GC отвечает за его вызов и очистку объекта из памяти.) Если разработчик забыл вызвать Dispose() метод объекта, то можно будет освободить неуправляемые ресурсы и, таким образом, избежать утечки..

Есть много причин, чтобы не делать этого, и множество способов ошибиться.Короче говоря, редко есть причина, почему вам нужно сделать это или хотеть сделать это

...