Какова цель 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())?
Какой сценарий использования, где это будет играть важную роль?
Спасибо!
Ответы
Ответ 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.