Обратите внимание, этот ответ касается .NET. Я вообще не знаю, как это делает Java.
Давайте начнем с добавления финализатора, точнее, того, что происходит, когда объект без единицы собирается.
Когда GC запускается и обнаруживает объекты, для которых нет корневых ссылок, они собираются.
Однако, если вы добавляете финализатор в класс, когда GC обнаруживает, что объект подходит для сбора, он помещается в список, потому что у него есть финализатор.
Этот список обрабатывается помимо обычного GC, и, поскольку объект теперь имеет корневую ссылку (этот список), он временно не может быть собран. Список обрабатывается путем итерации по нему и вызова всех финализаторов. Здесь есть много деталей, которые я приукрашиваю.
После вызова финализатора объекта объект удаляется из списка. Иногда позже, когда GC снова обнаруживает этот объект, хотя у него все еще есть метод finalizer в своем типе, объект был помечен, так что финализатор больше не нуждается в запуске, и объект теперь собирается, как если бы у него не было финализатор для начала.
Таким образом, добавление финализатора на самом деле не приведет к более быстрому сбору объекта, скорее это приведет к тому, что объект будет собран позже.
Единственный способ сделать объект пригодным для сбора - удалить все корневые ссылки на него.
Вызов Уничтожить также не имеет смысла в этом отношении. Dispose - это просто вызов метода, и его вызов никоим образом не помечает объект как подходящий для сбора. Если после вызова Dispose у вас все еще есть корневые ссылки на объект, он останется в памяти и не будет собран.
Однако, если в вашем классе есть метод Dispose и финализатор, метод Dispose обычно отменяет регистрацию объекта от финализации. По сути, вы говорите: «Утилизация теперь позаботилась обо всем, что будет делать финализатор, поэтому больше нет смысла вызывать финализатор». Если это произойдет, вызов метода Dispose, а затем удаление всех живых ссылок на объект сделает его пригодным для сбора и пропустит этап завершения.
На ваш второй вопрос.
Как я уже говорил выше, вам нужно удалить все корневые ссылки на объект. Корневая ссылка - это ссылка, которая может быть прослежена до чего-то, что живет в течение всей программы, будь то статические поля, локальные переменные в все еще действующих стеках вызовов и т. Д. После того, как все они ушли, объект пригоден для сбора.
Но GC в .NET действительно агрессивен. JITter будет хранить информацию вместе с кодом, сообщающим GC, какие части метода используют локальные переменные, и если переменная больше не используется, например, для последней части метода, даже если переменная по-прежнему ссылается на объект, переменная считается ненужной, и, таким образом, объект может быть собран.
Например, здесь:
public void Test()
{
object o = new object();
// do something else
}
В этом случае, пока переменная o
больше не используется в методе, во время этого кода «сделать что-то еще» объект в нем может быть собран.
JITter определит, когда программа работает в отладчике, а затем искусственно продлит время жизни всех переменных до конца их областей, так что вы можете проверять переменные, даже если они технически не считаются «живыми». Больше. Но когда не работает в отладчике, то, что o
выше явно не обнуляется, ничего не значит, объект все еще может быть собран.
Теперь, если o
было статическим полем, которое живет намного дольше, чем вызов метода, тогда да, явное задание ему значения null, конечно, поможет, потому что теперь вы удаляете корневые ссылки на объект.
Кроме того, если переменная будет использоваться позже в методе, вы можете помочь сделать текущий объект пригодным для сбора, установив для него значение null.( note Я не совсем уверен в этом, возможно, JITter может увидеть, что текущее значение не нужно, поэтому его можно собрать, потому что позже вы все равно перезапишете содержимое)
Итак, подведем итог:
- Не добавляйте финализатор, если он вам не нужен
- Вызов Dispose не имеет никакого отношения к тому, как скоро объект станет пригодным для сбора«пометить» объект как подходящий для коллекции, избавиться от всех корневых ссылок на него
- Вы можете помочь с коллекцией, явно установив переменные и поля в null, но для локальных переменных, которые больше не используются методом,это может не понадобиться (но не повредит)