Некоторые из других ответов на этот вопрос содержат неутешительное количество дезинформации, в то время как другие значительно усложняют проблему. Существует множество заблуждений относительно сборки мусора в .NET, и рассмотренные здесь теории, безусловно, не помогают решить проблему.
Прежде всего, профилирование использования памяти с помощью диспетчера задач Windows - огромная ошибка . Вы серьезно получите неверную информацию , и попытка изменить ваше приложение в соответствии с этой информацией только ухудшит ситуацию, а не улучшит ее. Если вы подозреваете, что у вас есть проблемы с производительностью (и очень сомнительно, что большинство приложений на самом деле будут иметь какие-либо проблемы), вам нужно инвестировать в надлежащий профилировщик памяти и использовать его вместо этого.
Во-вторых, весь смысл сборки мусора в том, что вам не нужно беспокоиться о подобных вещах . И вы не только не должны беспокоиться об этом, но вы также не должны беспокоиться об этом. Вы не должны делать или пытаться каким-либо образом управлять памятью вручную, когда пишете приложения для .NET Framework. Не поддавайтесь искушению возиться с внутренней работой сборщика мусора и крепко прижать пальцы к ушам, когда кто-нибудь скажет вам вызвать GC.Collect
вручную, чтобы вызвать сборку мусора. Полагаю, я не должен говорить никогда, но вряд ли есть причина 1017 *. У меня гораздо больше шансов быть подозреваемым кода, который вручную вызывает сборку мусора, чем что-либо еще.
Почему бы вам не запускать сборку мусора вручную? Что ж, помимо очевидного аргумента о том, что он в первую очередь лишает смысла использование управляемого языка, это связано с тем, что сборка мусора является чрезвычайно медленным и дорогостоящим процессом . Вы хотите, чтобы он работал как редко , насколько это возможно, для поддержания максимальной производительности. К счастью, программисты, которые реализовали алгоритмы сборки мусора, намного умнее и опытнее, чем вы или я: они разработали его для запуска только при необходимости , и не чаще этого. Вы не увидите преимущества более частого запуска, но вы увидите недостаток. Это должно быть совершенно непрозрачно для вас, как для программиста.
Единственное исключение - это когда вы работаете с неуправляемыми объектами, которые не собираются или управляются сборщиком мусора. Вы сможете распознать эти объекты, поскольку все они реализуют интерфейс IDisposable
, который предоставляет метод Dispose
для освобождения неуправляемых ресурсов. На объектах, которые предоставляют этот метод, вы должны вызывать его, как только вы закончите использовать объект. Или, что еще лучше, оберните объявление и использование объекта в using
оператор , который автоматически будет обрабатывать удаление объекта, независимо от того, что произойдет ( даже если в коде, где вы используете объект, например, возникает исключение).
Конечно, вы заметите, что несколько стандартных объектов в библиотеке Windows Forms реализуют метод IDisposable
. Например, вездесущий Form
класс предоставляет метод Dispose
. Однако это не обязательно означает, что вы несете ответственность за утилизацию этих предметов вручную. В общем, вам нужно только явно вызвать метод Dispose
для объектов, которые вы явно создаете - легко запомнить, верно? Объекты, созданные автоматически Framework, также автоматически уничтожаются Framework. Например, элементы управления, которые вы помещаете на объект Form
во время разработки, автоматически удаляются при размещении их формы контейнера. И Form
сами объекты автоматически удаляются, когда они закрыты. Это особенно относится к проблеме, поднятой в вашем вопросе. Документация для метода Form.Close
сообщает нам следующее:
Когда форма закрыта, все ресурсы, созданные внутри объекта, закрываются и форма удаляется.
[. , , ]
Два условия, когда форма не расположена на Close
, - это когда (1) она является частью приложения с интерфейсом с несколькими документами (MDI), а форма не отображается; и (2) вы отобразили форму, используя ShowDialog
. В этих случаях вам нужно будет вызвать Dispose
вручную, чтобы пометить все элементы управления формой для сборки мусора.
Обратите внимание, что, как правило, вам никогда не придется звонить Form.Dispose
вручную из своего кода. Пользователь не может закрыть дочернюю форму MDI, когда его родительский MDI не виден, и если вам случится закрыть форму самостоятельно в коде, когда его родительский элемент невидим, вы можете просто вставить вызов Form.Dispose
. Когда вы показываете форму как модальное диалоговое окно с использованием метода ShowDialog
, вы можете удобно заключить ее создание и использование в оператор using
.
Теперь напомним, что простой вызов метода Dispose
для объекта только высвобождает неуправляемые ресурсы и помечает объект как доступный для сборки мусора. Он не сразу освобождает память, требуемую этим объектом. Это важно, потому что именно на этом были сосредоточены ваши попытки профилирования памяти. Вы знаете, что объекты удаляются, потому что вы упоминаете, что переменные становятся недоступными для вас (вы говорите, что «теряете свои значения»). Это потому что вы не можете получить доступ к удаленным объектам. Это не обязательно подразумевает, однако, что память, которую они требовали, была полностью освобождена. Это работа сборщика мусора, которую мы уже установили, с которой вы не должны мириться. Он будет ожидать освобождения памяти до тех пор, пока приложение не будет бездействующим, или ему крайне необходимо повторно использовать этой памяти. В противном случае, он отложит сбор, и все в порядке .