Из документации Microsoft я знаю, что «основное» использование IDisposable
интерфейса - очистка неуправляемых ресурсов.
Для меня «неуправляемый» означает такие вещи, как соединения с базой данных, сокеты, дескрипторы окон и т. Д. Но я видел код, в котором Dispose()
метод реализован для освобождения управляемых ресурсов, что мне кажется избыточным, поскольку сборщик мусора должен позаботиться о это для тебя.
Например:
public class MyCollection : IDisposable
{
private List<String> _theList = new List<String>();
private Dictionary<String, Point> _theDict = new Dictionary<String, Point>();
// Die, clear it up! (free unmanaged resources)
public void Dispose()
{
_theList.clear();
_theDict.clear();
_theList = null;
_theDict = null;
}
Мой вопрос заключается в том, делает ли сборщик мусора свободную память используемой MyCollection
быстрее, чем обычно?
редактирование : до сих пор люди опубликовали несколько хороших примеров использования IDisposable для очистки неуправляемых ресурсов, таких как соединения с базой данных и растровые изображения. Но предположим, что _theList
в приведенном выше коде содержится миллион строк, и вы хотели освободить эту память сейчас , а не ждать сборщика мусора. Будет ли приведенный выше код выполнить это?
IDisposable
ничего не помечает.Dispose
Метод делает то , что он должен сделать , чтобы очистить ресурсы , используемые экземпляром. Это не имеет ничего общего с GC.IDisposable
. И именно поэтому я сказал, что принятый ответ не отвечает на заданный OP вопрос (и последующее редактирование) о том, поможет ли IDisposable в <i> освобождении памяти </ i>. ТакIDisposable
как не имеет никакого отношения к освобождению памяти, а только к ресурсам, то, как вы сказали, нет нужды вообще устанавливать для управляемых ссылок значение null, как это делал OP в своем примере. Таким образом, правильный ответ на его вопрос: «Нет, это не помогает освободить память быстрее. Фактически, это не помогает освободить память вообще, только ресурсы». Но в любом случае, спасибо за ваш вклад.Ответы:
Задача Dispose - освободить неуправляемые ресурсы. Это нужно сделать в какой-то момент, иначе они никогда не будут очищены. Сборщик мусора не знает, как вызвать
DeleteHandle()
переменную типаIntPtr
, он не знает, нужно ли ему вызыватьDeleteHandle()
.Созданный вами объект должен предоставить некоторый метод, который может вызывать внешний мир, для очистки неуправляемых ресурсов. Метод можно назвать как угодно:
или
Но вместо этого есть стандартизированное имя для этого метода:
Был даже создан интерфейс
IDisposable
, который имеет только один метод:Таким образом, вы заставляете ваш объект предоставлять
IDisposable
интерфейс, и таким образом вы обещаете, что написали этот единственный метод для очистки ваших неуправляемых ресурсов:И вы сделали. За исключением того, что вы можете сделать лучше.
Что если ваш объект выделил 250MB System.Drawing.Bitmap (то есть, управляемый .NET класс Bitmap) в качестве буфера кадра? Конечно, это управляемый объект .NET, и сборщик мусора освободит его. Но вы действительно хотите оставить 250 МБ памяти, просто сидя там - ожидая, когда сборщик мусора в конце концов придет и освободит его? Что если есть открытое соединение с базой данных ? Конечно, мы не хотим, чтобы это соединение оставалось открытым, ожидая, пока GC завершит объект.
Если пользователь вызвал
Dispose()
(то есть он больше не планирует использовать объект), почему бы не избавиться от этих расточительных растровых изображений и соединений с базой данных?Итак, теперь мы будем:
Итак, давайте обновим наш
Dispose()
метод, чтобы избавиться от этих управляемых объектов:И все хорошо, кроме того, что вы можете сделать лучше !
Что если человек забыл позвонить
Dispose()
на ваш объект? Тогда они будут пропускать некоторые неуправляемые ресурсы!Если человек забыл позвонить
Dispose()
, мы все равно можем сохранить его сало! У нас все еще есть способ вызвать это для них: когда сборщик мусора, наконец, приступает к освобождению (т.е. завершению) нашего объекта.Уничтожение нашего объекта сборщиком мусора - идеальное время, чтобы освободить эти надоедливые неуправляемые ресурсы. Мы делаем это путем переопределения
Finalize()
метода.Но в этом коде есть ошибка. Видите ли, сборщик мусора работает в фоновом потоке ; Вы не знаете порядок, в котором уничтожены два объекта. Вполне возможно, что в вашем
Dispose()
коде управляемого объекта, от которого вы пытаетесь избавиться (потому что вы хотели быть полезным), больше нет:Так что вам нужен способ
Finalize()
сказать,Dispose()
что он не должен касаться каких-либо управляемых ресурсов (потому что их там больше не может быть ), при этом освобождая неуправляемые ресурсы.Стандартный шаблон для этого - иметь
Finalize()
иDispose()
оба вызывать третий (!) Метод; где вы передаете логическое выражение, если вы вызываете егоDispose()
(в отличие отFinalize()
), то есть безопасно освобождать управляемые ресурсы.Этот внутренний метод может иметь произвольное имя, например «CoreDispose» или «MyInternalDispose», но традиционно его называют
Dispose(Boolean)
:Но более полезное имя параметра может быть:
И вы измените свою реализацию
IDisposable.Dispose()
метода на:и ваш финализатор для:
И все хорошо, кроме того, что вы можете сделать лучше !
Если пользователь вызывает
Dispose()
ваш объект, то все было убрано. Позже, когда придет сборщик мусора и вызовет Finalize, он снова вызоветDispose
.Это не только расточительно, но если у вашего объекта есть ненужные ссылки на объекты, которые вы уже удалили из последнего вызова
Dispose()
, вы попытаетесь утилизировать их снова!Вы заметите, что в моем коде я осторожно удалял ссылки на объекты, которые я выбрал, поэтому я не пытаюсь вызвать
Dispose
ссылку на ненужный объект. Но это не остановило незаметную ошибку.Когда пользователь вызывает
Dispose()
: дескриптор CursorFileBitmapIconServiceHandle уничтожается. Позже, когда запускается сборщик мусора, он снова попытается уничтожить ту же ручку.Способ исправить это - сказать сборщику мусора, что ему не нужно беспокоиться о завершении объекта - его ресурсы уже очищены, и больше не требуется никакой работы. Вы можете сделать это по телефону
GC.SuppressFinalize()
вDispose()
методе:Теперь, когда пользователь позвонил
Dispose()
, мы имеем:В GC нет смысла запускать финализатор - обо всем позаботились.
Не могу ли я использовать Finalize для очистки неуправляемых ресурсов?
Документация для
Object.Finalize
говорит:Но в документации MSDN также сказано
IDisposable.Dispose
:Так что это? Какое место для меня, чтобы очистить неуправляемые ресурсы? Ответ:
Вы, конечно, можете поместить свою неуправляемую очистку в финализатор:
Проблема в том, что вы понятия не имеете, когда сборщик мусора дойдет до завершения вашего объекта. Ваш непредоставленные удалось, не-необходимости, Неиспользуемая родные ресурсы будут придерживаться вокруг , пока сборщик мусора в конечном счете не работает. Затем он вызовет ваш метод финализатора; очистка неуправляемых ресурсов. Документация Object.Finalize указывает на это:
Это преимущество использования
Dispose
для очистки неуправляемых ресурсов; Вы узнаете и контролируете, когда неуправляемые ресурсы очищаются. Их уничтожение является «детерминированным» .Чтобы ответить на ваш первоначальный вопрос: почему бы не освободить память сейчас, а не тогда, когда GC решит это сделать? У меня есть программное обеспечение для распознавания лиц, которое теперь должно избавиться от 530 МБ внутренних изображений , поскольку они больше не нужны. Когда мы этого не сделаем: машина останавливается.
Бонус Чтение
Для тех, кто любит стиль этого ответа (объясняя почему , и как это становится очевидным), я предлагаю вам прочитать Главу 1 «Основного COM» Дона Бокса:
На 35 страницах он объясняет проблемы использования бинарных объектов и изобретает COM на ваших глазах. Как только вы поймете причину COM, оставшиеся 300 страниц станут очевидными и просто детализируют реализацию Microsoft.
Я думаю, что каждый программист, который когда-либо имел дело с объектами или COM, должен, по крайней мере, прочитать первую главу. Это лучшее объяснение чего-либо.
Дополнительное чтение бонусов
Когда все, что вы знаете, неправильно , Эрик Липперт
источник
null
. Во-первых, это означает, что вы не можете их сделатьreadonly
, а во-вторых, вы должны делать очень уродливые!=null
проверки (как в примере кода). У вас мог быть флагdisposed
, но легче об этом не беспокоиться. .NET GC достаточно агрессивен, так что ссылка на полеx
больше не будет считаться «использованной» к тому времени, когда она пройдетx.Dispose()
строку.IDisposable
часто используется для использованияusing
оператора и использования простого способа детерминированной очистки управляемых объектов.источник
Цель шаблона Dispose - предоставить механизм для очистки как управляемых, так и неуправляемых ресурсов, и когда это произойдет, зависит от того, как вызывается метод Dispose. В вашем примере использование Dispose на самом деле ничего не делает для удаления, поскольку очистка списка не влияет на удаление этой коллекции. Аналогичным образом, вызовы для установки переменных в null также не влияют на сборщик мусора.
Вы можете взглянуть на эту статью для более подробной информации о том, как реализовать шаблон Dispose, но в основном это выглядит так:
Наиболее важным здесь является метод Dispose (bool), который на самом деле работает при двух разных обстоятельствах:
Проблема с тем, чтобы просто позволить GC позаботиться о выполнении очистки, заключается в том, что у вас нет реального контроля над тем, когда GC будет запускать цикл сбора (вы можете вызвать GC.Collect (), но на самом деле не следует), поэтому ресурсы могут остаться вокруг дольше, чем нужно. Помните, что вызов Dispose () на самом деле не вызывает цикл сбора или каким-либо образом заставляет GC собирать / освобождать объект; он просто предоставляет средства для более детерминированной очистки используемых ресурсов и сообщает GC, что эта очистка уже выполнена.
Весь смысл IDisposable и шаблона dispose не заключается в немедленном освобождении памяти. Единственный раз, когда у вызова Dispose даже есть шанс немедленно освободить память, это когда он обрабатывает сценарий == false и манипулирует неуправляемыми ресурсами. Для управляемого кода память фактически не будет возвращена до тех пор, пока GC не выполнит цикл сбора, который вы действительно не можете контролировать (кроме вызова GC.Collect (), о котором я уже упоминал, не очень хорошая идея).
Ваш сценарий на самом деле недопустим, поскольку строки в .NET не используют никаких неуправляемых ресурсов и не реализуют IDisposable, поэтому нет способа заставить их «очиститься».
источник
После вызова Dispose не должно быть никаких дальнейших вызовов методов объекта (хотя объект должен допускать дальнейшие вызовы Dispose). Поэтому пример в вопросе глупый. Если вызывается Dispose, то сам объект может быть отброшен. Таким образом, пользователь должен просто отбросить все ссылки на весь этот объект (установить для него значение null), и все связанные с ним внутренние объекты будут автоматически очищены.
Что касается общего вопроса об управляемых / неуправляемых и обсуждения в других ответах, я думаю, что любой ответ на этот вопрос должен начинаться с определения неуправляемого ресурса.
Все сводится к тому, что есть функция, которую вы можете вызвать, чтобы привести систему в состояние, и есть другая функция, которую вы можете вызвать, чтобы вывести ее из этого состояния. Теперь, в типичном примере, первая может быть функцией, которая возвращает дескриптор файла, а вторая может быть вызовом
CloseHandle
.Но - и это ключ - они могут быть любой подходящей парой функций. Один создает государство, другой разрушает его. Если состояние было построено, но еще не снесено, то существует экземпляр ресурса. Вы должны организовать, чтобы демонтаж происходил в нужное время - ресурс не управляется CLR. Единственный автоматически управляемый тип ресурса - это память. Есть два вида: GC и стек. Типы значений управляются стеком (или путём перехода внутри ссылочных типов), а ссылочные типы управляются GC.
Эти функции могут вызывать изменения состояния, которые могут свободно чередоваться, или могут нуждаться в идеальном вложении. Изменения состояния могут быть поточно-безопасными или нет.
Посмотрите на пример в вопросе правосудия. Изменения в отступе файла журнала должны быть идеально вложены, иначе все пойдет не так. Также они вряд ли будут безопасны.
Можно собрать мусора, чтобы очистить ваши неуправляемые ресурсы. Но только если функции изменения состояния являются поточно-ориентированными и два состояния могут иметь время жизни, которое перекрывается любым образом. Таким образом, пример ресурса правосудия НЕ должен иметь финализатор! Это просто никому не поможет.
Для таких видов ресурсов вы можете просто реализовать
IDisposable
без финализатора. Финализатор абсолютно необязателен - так и должно быть. Это скрыто или даже не упоминается во многих книгах.Затем вы должны использовать это
using
утверждение, чтобы иметь возможность убедиться, что оноDispose
вызывается. По сути, это похоже на соединение со стеком (так как финализатор для GC,using
это для стека).Недостающая часть заключается в том, что вы должны вручную написать Dispose и вызвать его для ваших полей и вашего базового класса. Программисты C ++ / CLI не должны этого делать. Компилятор пишет это для них в большинстве случаев.
Существует альтернатива, которую я предпочитаю для состояний, которые прекрасно встраиваются и не являются поточно-ориентированными (кроме всего прочего, избегание IDisposable избавляет вас от проблемы с кем-то, кто не может устоять перед добавлением финализатора в каждый класс, реализующий IDisposable). ,
Вместо того, чтобы писать класс, вы пишете функцию. Функция принимает делегата для обратного вызова:
И тогда простой пример будет:
Передаваемая лямбда-функция служит блоком кода, поэтому вы создаете свою собственную управляющую структуру, которая служит той же цели
using
, за исключением того, что вы больше не рискуете злоупотреблять вызывающей стороной. Они никак не могут очистить ресурс.Этот метод менее полезен, если ресурс того типа, который может иметь перекрывающиеся времена жизни, потому что тогда вы хотите иметь возможность построить ресурс A, затем ресурс B, затем убить ресурс A, а затем убить ресурс B. Вы не можете сделать это если вы заставили пользователя идеально вложить это. Но тогда вам нужно использовать
IDisposable
(но все же без финализатора, если вы не реализовали безопасность потоков, что не является бесплатным).источник
enter
иexit
является основой того, как я думаю о ресурсе. Подписка / отказ от подписки на события должны вписываться в это без труда. С точки зрения ортогональных / взаимозаменяемых характеристик он практически неотличим от утечки памяти. (Это неудивительно, поскольку подписка просто добавляет объекты в список.)Сценарии, которые я использую IDisposable: очистить неуправляемые ресурсы, отписаться о событиях, закрыть соединения
Идиома, которую я использую для реализации IDisposable ( не потокобезопасен ):
источник
Да, этот код является полностью избыточным и ненужным, и он не заставляет сборщик мусора делать то, что он не делал бы иначе (когда экземпляр MyCollection выходит из области видимости, то есть.) Особенно это касается
.Clear()
вызовов.Ответ на ваши изменения: вроде. Если я сделаю это:
Это функционально идентично этому для целей управления памятью:
Если вам действительно очень нужно освободить память в этот самый момент, звоните
GC.Collect()
. Там нет причин делать это здесь, хотя. Память будет освобождена, когда это необходимо.источник
Если
MyCollection
вы все равно будете собирать мусор, вам не нужно его утилизировать. Это просто увеличит производительность ЦП, чем необходимо, и может даже сделать недействительным некоторый предварительно рассчитанный анализ, который сборщик мусора уже выполнил.Я использую
IDisposable
для таких вещей, как обеспечение правильного расположения потоков наряду с неуправляемыми ресурсами.РЕДАКТИРОВАТЬ В ответ на комментарий Скотта:
Концептуально GC поддерживает представление графа ссылок объекта и всех ссылок на него из стековых фреймов потоков. Эта куча может быть довольно большой и занимать много страниц памяти. В качестве оптимизации GC кеширует свой анализ страниц, которые вряд ли изменятся очень часто, чтобы избежать ненужного повторного сканирования страницы. GC получает уведомление от ядра при изменении данных на странице, поэтому он знает, что страница грязная и требует повторного сканирования. Если коллекция находится в Gen0, то вероятно, что другие вещи на странице тоже меняются, но это менее вероятно в Gen1 и Gen2. Как ни странно, эти перехватчики не были доступны в Mac OS X для команды, которая перенесла GC на Mac, чтобы заставить плагин Silverlight работать на этой платформе.
Еще один момент против ненужной утилизации ресурсов: представьте ситуацию, когда процесс выгружается. Представьте также, что процесс запущен в течение некоторого времени. Скорее всего, многие страницы памяти этого процесса были перенесены на диск. По крайней мере, они больше не находятся в кеше L1 или L2. В такой ситуации приложение, которое выгружается, не имеет смысла выгружать все эти данные и кодовые страницы обратно в память, чтобы «высвободить» ресурсы, которые будут освобождены операционной системой в любом случае, когда процесс завершится. Это относится к управляемым и даже определенным неуправляемым ресурсам. Только ресурсы, которые поддерживают не фоновые потоки, должны быть удалены, иначе процесс останется живым.
Теперь во время обычного выполнения существуют временные ресурсы, которые необходимо правильно очистить (так как @fezmonkey указывает на соединения с базой данных, сокеты, дескрипторы окон ), чтобы избежать неуправляемых утечек памяти. Это те вещи, которые должны быть уничтожены. Если вы создаете какой-то класс, которому принадлежит поток (и я имею в виду, что он создал его и, следовательно, отвечает за его остановку, по крайней мере, благодаря моему стилю кодирования), то этот класс, скорее всего, должен реализовать
IDisposable
и разрушить поток во времяDispose
..NET Framework использует
IDisposable
интерфейс как сигнал, даже предупреждая разработчиков, что этот класс должен быть удален. Я не могу думать о каких-либо типах в рамках, которые реализуютIDisposable
(исключая явные реализации интерфейса), где удаление является необязательным.источник
Dispose()
вызовов см .: stackoverflow.com/questions/913228/…В приведенном вами примере он все еще не «освобождает память сейчас». Вся память является сборщиком мусора, но это может позволить собирать память в более раннем поколении . Вы должны выполнить несколько тестов, чтобы быть уверенным.
Принципы разработки структуры - это руководящие принципы, а не правила. Они говорят вам, для чего прежде всего предназначен интерфейс, когда его использовать, как его использовать, а когда нет.
Однажды я прочитал код, который был простым RollBack () при ошибке с использованием IDisposable. Класс MiniTx, приведенный ниже, будет проверять флаг Dispose () и, если
Commit
вызов не произойдет, он будет вызыватьRollback
сам себя. Это добавило слой косвенности, что значительно облегчило понимание и поддержку вызывающего кода. Результат выглядел примерно так:Я также видел, что тайминг / логирование кода делают то же самое. В этом случае метод Dispose () остановил таймер и зарегистрировал, что блок вышел.
Итак, вот пара конкретных примеров, которые не выполняют никакой неуправляемой очистки ресурсов, но успешно используют IDisposable для создания более чистого кода.
источник
Если вы хотите удалить прямо сейчас , используйте неуправляемую память .
Видеть:
источник
Я не буду повторять обычные вещи об использовании или освобождении неуправляемых ресурсов, которые все были рассмотрены. Но я хотел бы указать на то, что кажется распространенным заблуждением.
Учитывая следующий код
Я понимаю, что реализация Disposable не соответствует текущим рекомендациям, но, надеюсь, вы все поняли идею.
Теперь, когда вызывается Dispose, сколько памяти освобождается?
Ответ: нет.
Вызов Dispose может освободить неуправляемые ресурсы, он НЕ МОЖЕТ вернуть управляемую память, это может сделать только GC. Это не значит, что вышеизложенное не является хорошей идеей, следуя приведенному выше шаблону, на самом деле все еще хорошая идея. После запуска Dispose ничто не мешает GC повторно запросить память, которая использовалась _Large, даже если экземпляр LargeStuff все еще находится в области видимости. Строки в _Large также могут относиться к поколению 0, но экземпляр LargeStuff может относиться к поколению 2, поэтому снова память будет востребована раньше.
Однако нет смысла добавлять финализатор для вызова метода Dispose, показанного выше. Это просто ЗАДЕРЖИТ повторное требование памяти, чтобы позволить финализатору работать.
источник
LargeStuff
был достаточно длинным, чтобы попасть в Поколение 2, и если он_Large
содержит ссылку на вновь созданную строку, которая находится в Поколении 0, то если экземпляр этого объектаLargeStuff
был оставлен без обнуления_Large
, тогда строка, на которую ссылается_Large
будет храниться до следующей коллекции Gen2. Обнуление_Large
может привести к удалению строки в следующей коллекции Gen0. В большинстве случаев обнуление ссылок бесполезно, но в некоторых случаях это может принести некоторую пользу.Помимо своего основного применения в качестве способа контролировать срок службы в системных ресурсах (полностью покрыта удивительным ответом Яна , престижность!), То IDisposable / с использованием комбы также может быть использован для определения области изменения состояния (критических) глобальных ресурсов : консоли , то потоки , то процесс , любой глобальный объект как экземпляр приложения .
Я написал статью об этом шаблоне: http://pragmateek.com/c-scope-your-global-state-changes-with-idisposable-and-the-using-statement/
Он иллюстрирует, как вы можете защитить некоторые часто используемые глобальные состояния многоразовым и читаемым способом: цвета консоли , текущую культуру потоков , свойства объекта приложения Excel ...
источник
Во всяком случае, я ожидал бы, что код будет менее эффективным, чем когда он пропущен.
Вызывать методы Clear () не нужно, и GC, вероятно, не сделал бы этого, если бы Dispose этого не делал ...
источник
Есть вещи, которые эта
Dispose()
операция делает в примере кода, которые могут иметь эффект, который не произойдет из-за обычного GCMyCollection
объекта.Если объекты, на которые ссылаются
_theList
или на_theDict
которые ссылаются другие объекты, то этот объектList<>
илиDictionary<>
объект не будут подлежать сбору, но внезапно не будут иметь содержимого. Если бы не было операции Dispose (), как в примере, эти коллекции все равно содержали бы свое содержимое.Конечно, если бы это была ситуация, я бы назвал это неправильным дизайном - я просто указываю (педантично, я полагаю), что
Dispose()
операция может быть не полностью избыточной, в зависимости от того, есть ли другие варианты использованияList<>
илиDictionary<>
нет показано на фрагменте.источник
Одна из проблем большинства дискуссий о «неуправляемых ресурсах» заключается в том, что они на самом деле не определяют термин, но, похоже, подразумевают, что он как-то связан с неуправляемым кодом. Хотя верно, что многие типы неуправляемых ресурсов взаимодействуют с неуправляемым кодом, размышления о неуправляемых ресурсах в таких терминах бесполезны.
Вместо этого следует признать, что общего имеют все управляемые ресурсы: все они влекут за собой объект, требующий, чтобы какое-то внешнее «что-то» сделало что-то от его имени, в ущерб некоторым другим «вещам», а другой объект согласился сделать это до тех пор, пока дальнейшего уведомления. Если бы объект был оставлен и исчез без следа, ничто никогда не сообщило бы этой внешней «вещи», что ей больше не нужно изменять свое поведение от имени объекта, которого больше не существует; следовательно, полезность вещи будет постоянно уменьшаться.
Таким образом, неуправляемый ресурс представляет собой соглашение какой-то внешней «вещи» об изменении своего поведения от имени объекта, что бесполезно ухудшает полезность этой внешней «вещи», если объект был оставлен и прекратил существование. Управляемый ресурс - это объект, который является бенефициаром такого соглашения, но который подписался на получение уведомления об отказе от него и который будет использовать такое уведомление для наведения порядка в своих делах до его уничтожения.
источник
IDisposable
хорошо для отписки от событий.источник
Первое определение. Для меня неуправляемый ресурс означает некоторый класс, который реализует интерфейс IDisposable или что-то созданное с использованием вызовов в dll. GC не знает, как обращаться с такими объектами. Если класс имеет, например, только типы значений, я не рассматриваю этот класс как класс с неуправляемыми ресурсами. Для своего кода я следую следующим практикам:
Следующий шаблон демонстрирует то, что я описал словами как пример кода:
источник
is IDisposable
сам по себе должен рассматриваться как неуправляемый ресурс? Это не кажется правильным. Также, если тип implmenting является чистым типом значения, вы, вероятно, предполагаете, что его не нужно удалять. Это также кажется неправильным.Данный пример кода не является хорошим примером для
IDisposable
использования. Очистка словаря обычно не должна идти вDispose
метод. Элементы словаря будут очищены и удалены, когда они выйдут из области видимости.IDisposable
реализация необходима для освобождения памяти / обработчиков, которые не будут освобождены / освобождены даже после того, как они выйдут из области видимости.В следующем примере показан хороший пример шаблона IDisposable с некоторым кодом и комментариями.
источник
Наиболее оправданный вариант использования для удаления управляемых ресурсов - это подготовка к GC для восстановления ресурсов, которые иначе никогда бы не были собраны.
Ярким примером являются круговые ссылки.
Хотя рекомендуется использовать шаблоны, которые избегают циклических ссылок, если вы в конечном итоге получите (например) «дочерний» объект, который имеет ссылку на свой «родительский», это может остановить сбор GC родительского объекта, если вы просто откажетесь ссылка и полагаться на GC - плюс, если вы реализовали финализатор, он никогда не будет вызываться.
Единственный способ обойти это - вручную разорвать циклические ссылки, установив для родительских ссылок значение null для дочерних элементов.
Реализация IDisposable на родителя и детей является лучшим способом сделать это. Когда Dispose вызывается для Parent, вызывается Dispose для всех дочерних элементов, а в дочернем методе Dispose установите для родительских ссылок значение null.
источник
WeakReference
, система проверит флаг, который указывает, что в последнем цикле GC была найдена прямая корневая ссылка и либо добавит объект в очередь объектов, нуждающихся в немедленной финализации, освободит объект из кучи больших объектов, либо сделает недействительной слабую ссылку. Циркулярные ссылки не будут поддерживать жизнь объектов, если другие ссылки не существуют.Я вижу, что многие ответы изменились, чтобы поговорить об использовании IDisposable как для управляемых, так и для неуправляемых ресурсов. Я бы предложил эту статью как одно из лучших объяснений того, как на самом деле следует использовать IDisposable.
https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About
Для актуального вопроса; Если вы используете IDisposable для очистки управляемых объектов, которые занимают много памяти, короткий ответ будет отрицательным . Причина в том, что после удаления IDisposable вы должны позволить ему выйти из области видимости. На этом этапе любые дочерние объекты, на которые ссылаются, также находятся вне области и будут собраны.
Единственное реальное исключение - это если у вас много памяти, связанной в управляемых объектах, и вы заблокировали этот поток, ожидая завершения какой-либо операции. Если эти объекты не понадобятся после завершения этого вызова, то установка этих ссылок на null может позволить сборщику мусора быстрее их собрать. Но этот сценарий будет представлять плохой код, который необходимо реорганизовать, а не вариант использования IDisposable.
источник