Я пишу этот пост как последнюю часть серии Управление памятью в C # (« Часть 1 и Часть 2 )». В этом сообщении объясняется, что делает Сборщик мусора и как он работает в среде .NET. (Большая часть представленной здесь информации цитируется из документации Microsoft)

Во-первых, давайте начнем с Common Language Runtime.

Общеязыковая среда выполнения

.NET Framework предоставляет среду выполнения, называемую Common Language Runtime (CLR),, которая запускает код и предоставляет службы, упрощающие процесс разработки.

На следующем рисунке показана связь среды CLR и библиотеки классов с вашими приложениями и системой в целом.

Компоненты CLR:

В среде CLR сборщик мусора служит автоматическим диспетчером памяти. C # и другие языки поверх CLR собираются сборщиком мусора.

Сборщик мусора

Сборщик мусора (GC) .NET управляет выделением и освобождением памяти для вашего приложения.

GC дает следующие преимущества:

  • Позволяет разрабатывать приложение, не освобождая память.
  • Эффективно распределяет объекты в управляемой куче.
  • Восстанавливает объекты, которые больше не используются, очищает их память и сохраняет доступную память для будущих распределений.
  • Обеспечивает безопасность памяти, гарантируя, что объект не может использовать содержимое другого объекта.

Все процессы на одном компьютере используют одну и ту же физическую память. У каждого процесса есть свое собственное отдельное виртуальное адресное пространство. Как разработчик приложений вы работаете только с виртуальным адресным пространством и никогда не манипулируете физической памятью напрямую. GC выделяет и освобождает виртуальную память в управляемой куче.

Кучу можно рассматривать как скопление двух куч: кучи больших объектов и кучи малых объектов. Куча больших объектов содержит очень большие объекты размером 85 000 байт и более (Объекты в куче больших объектов обычно представляют собой массивы).

Сборка мусора запускается, когда выполняется одно из следующих условий:

  • В системе мало физической памяти.
  • Объем памяти, используемый выделенными объектами в управляемой куче, превышает допустимый порог.
  • Вызывается метод GC.Collect. (Почти во всех случаях вам не нужно вызывать этот метод, потому что сборщик мусора работает непрерывно. Этот метод в основном используется для уникальных ситуаций и тестирования.)

Перед запуском сборки мусора все управляемые потоки приостанавливаются, за исключением потока, который запустил сборку мусора.

Поколения

В 1984 году Дэвид Ангар выдвинул гипотезу поколений, которая породила поколений сборщиков мусора:

Молодые объекты умирают молодыми. Поэтому алгоритм рекультивации не должен тратить время на старые объекты.

Копирование выживших дешевле сканирования трупов.

Куча организована по поколениям, поэтому она может обрабатывать долгоживущие и недолговечные объекты. В куче есть три поколения объектов:

Поколение 0: это самое молодое поколение, содержащее недолговечные объекты. Примером недолговечного объекта является временная переменная. Сборка мусора чаще всего происходит в этом поколении.

Недавно размещенные объекты образуют новое поколение объектов и неявно являются коллекциями Gen 0, если только они не являются большими объектами, и в этом случае они помещаются в кучу больших объектов в Коллекция Gen 2.

Большинство объектов отправляются на сборку мусора в Gen 0 и не доживают до следующего поколения. Объекты, оставшиеся после сборки мусора Gen 0, переводятся в Gen 1.

Поколение 1: это поколение содержит недолговечные объекты и действует как буфер между короткоживущими объектами и долгоживущие объекты. Объекты, оставшиеся после сборки мусора Gen 1, переводятся в Gen 2.

Поколение 2. Это поколение содержит долгоживущие объекты. Примером объекта-долгожителя является объект в серверном приложении, который содержит статические данные, живущие на протяжении всего процесса. Объекты, прошедшие сборку мусора Gen 2, остаются в Gen 2.

Собирать поколение означает собирать предметы в этом поколении и во всех его младших поколениях. Сборка мусора Gen 2 также известна как полная сборка мусора, поскольку она освобождает все объекты во всех поколениях.

Как работает сборщик мусора

Сборка мусора состоит из следующих этапов:

Маркировка. Находит и создает список всех живых объектов.

Перемещение: обновляет ссылки на объекты, которые будут уплотнены.

Уплотнение: освобождает пространство, занимаемое мертвыми объектами, и уплотняет уцелевшие объекты. На этапе уплотнения объекты, пережившие сборку мусора, перемещаются к более старому концу сегмента. (Обычно куча больших объектов не сжимается, поскольку копирование больших объектов снижает производительность.)

GC использует следующую информацию, чтобы определить, живы ли объекты:

  • Корни стека: переменные стека, предоставляемые JIT-компилятором и обходчиком стека.
  • Дескрипторы сборки мусора: дескрипторы, которые указывают на управляемые объекты и могут быть выделены пользовательским кодом или средой CLR.
  • Статические данные: статические объекты в доменах приложений, которые могут ссылаться на другие объекты.

Кроме того, существуют неуправляемые ресурсы, такие как файловые потоки, подключения к сети / базе данных, о которых вам нужно позаботиться. В этом случае вам нужно использовать Finalizer & Dispose. Вы можете обратиться к этому посту для получения дополнительной информации.

Наконец, я рекомендую вам посмотреть видео ниже, которое наглядно объясняет тему с очень полезной демонстрацией в конце.

Надеюсь, вы нашли этот пост полезным и легким для понимания. Как я уже упоминал в начале, это последняя часть серии Управление памятью C #. Если вам интересно, вы можете прочитать и другие сообщения (Часть 1 и Часть 2).

КОНЕЦ :)

Ссылки

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals

https://chodounsky.net/2017/05/03/garbage-collection-in-c-sharp/