Одна из причин, по которой у вас несколько поколений в сборщике мусора, - это избегание потери памяти из-за фрагментации.
Каждый вызов функции может означать создание и удаление коллекции нескольких объектов, поэтому куча памяти для вашей программы имеет тенденцию очень быстро фрагментироваться. Это оставляет дыры позади, которые не очень полезны. В результате ваша программа должна периодически подвергаться фрагментации, как жесткий диск. Это часть того, что происходит во время сбора.
Когда объект переживает коллекцию, он перемещается в более долгоживущее поколение по теории, что если он выжил в одной коллекции, он, вероятно, выживет в других. Таким образом, последующие поколения имеют меньший оборот и не так много фрагментированы. Это означает, что ваша программа тратит меньше времени на жонглирование, чтобы очистить дыры и тратить меньше памяти. Это также улучшение по сравнению с традиционным управлением памятью (malloc / free или new / delete), которое позволяет операционной системе управлять любой фрагментацией памяти.
Причина, по которой объект сохраняется в коллекции, заключается в том, что где-то что-то еще находится в области видимости и содержит ссылку на этот объект. Есть несколько способов заставить это произойти, а затем забыть о ссылке, так что возможно «утечка» памяти в управляемом коде.
Иногда люди испытывают искушение позвонить GC.Collect()
, чтобы заставить сборщика мусора что-нибудь почистить. Возможно, они обнаружили утечку или думают, что память становится слишком фрагментированной. Вы должны сопротивляться этим побуждениям. Хотя сборка мусора в .Net не идеальна, она очень хороша и почти наверняка намного лучше очищает память, чем вы. Скорее всего, если объект можно и нужно собирать, он будет. Помните, что вызов GC.Collect()
на самом деле может усугубить ситуацию, помогая сборщику мусора перемещать объекты до более высокого поколения и, таким образом, держать их вокруг дольше, чем они могли бы быть.
Вместо этого, если вы подозреваете, что у вас есть утечка, найдите в своем собственном коде что-то вроде глобальной или статической переменной, которая может содержать ссылку на множество других элементов. Единственный раз, когда вы должны вызывать GC.Collect()
, это когда у вас есть информация о природе программы, которая недоступна сборщику мусора, и это довольно редко, поскольку GC знает каждую созданную вами ссылку.
«Закрепление» - это когда вам нужно передать объект в неуправляемую библиотеку. Сборщик мусора может перемещать физическое местоположение объекта в памяти, поэтому вам нужно «закрепить» его в одном месте, иначе указатель, используемый неуправляемой библиотекой, может стать недействительным. Закрепленный объект не может быть собран, поэтому не следует закреплять объект дольше, чем необходимо.