Что такое сборщик мусора c
Перейти к содержимому

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

  • автор:

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

Сборщик мусора .NET управляет выделением и освобождением памяти для приложения. При каждом создании объекта среда CLR выделяет память для объекта из управляемой кучи. Пока в управляемой куче есть доступное адресное пространство, среда выполнения продолжает выделять пространство для новых объектов. Тем не менее ресурсы памяти не безграничны. В конечном счете сборщику мусора необходимо выполнить сбор, чтобы освободить память. Механизм оптимизации сборщика мусора определяет наилучшее время для выполнения сбора, основываясь на выполненных операциях выделения памяти. Когда сборщик мусора выполняет сборку, он проверяет наличие объектов в управляемой куче, которые больше не используются приложением, а затем выполняет необходимые операции, чтобы освободить память.

Заголовок Описание
Основы сборки мусора Описание работы сборки мусора, выделения объектов в управляемой куче и других базовых понятий.
Сборка мусора рабочей станции и сборка мусора сервера Описывает различия между сборкой мусора рабочей станции для клиентских приложений и сборкой мусора сервера для серверных приложений.
Фоновая сборка мусора Описывает фоновую сборку мусора, которая представляет собой сборку объектов поколения 0 и 1 во время сборки объектов поколения 2.
Куча больших объектов Описывает кучу больших объектов (LOH) и то, как для них выполняется сборка мусора.
Сборка мусора и производительность Проверки производительности, которые можно использовать для диагностики проблем со сборкой мусора и производительностью.
Индуцированные коллекции Описание выполнения сборки мусора.
Режимы задержки Описание режимов, которые определяют степень вмешательства сборщика мусора.
Оптимизация совместного размещения веб-сайтов Способы оптимизации сборки мусора на серверах, совместно используемыми небольшими веб-узлами.
Уведомления о сборке мусора Определение необходимости полной сборки мусора и времени завершения этой операции.
Отслеживание ресурсов домена приложения Способы наблюдения за использованием ЦП и памяти доменом приложения.
Слабые ссылки Описание функциональных возможностей, которые позволяют сборщику мусора обрабатывать объект, разрешая при этом приложению получать доступ к этому объекту.

Справочник

  • System.GC
  • System.GCCollectionMode
  • System.GCNotificationStatus
  • System.Runtime.GCLatencyMode
  • System.Runtime.GCSettings
  • GCSettings.LargeObjectHeapCompactionMode
  • Object.Finalize
  • System.IDisposable

См. также

Обратная связь

Были ли сведения на этой странице полезными?

Сборка мусора, управление памятью и указатели

Ранее в теме Типы значений и ссылочные типы мы рассматривали отдельные типы данных и как они располагаются в памяти. Так, при использовании переменных типов значений в методе, все значения этих переменных попадают в стек. После завершения работы метода стек очищается.

При использовании же ссылочных типов, например, объектов классов, для них также будет отводиться место в стеке, только там будет храниться не значение, а адрес на участок памяти в хипе или куче, в котором и будут находиться сами значения данного объекта. И если объект класса перестает использоваться, то при очистке стека ссылка на участок памяти также очищается, однако это не приводит к немедленной очистке самого участка памяти в куче. Впоследствии сборщик мусора (garbage collector) увидит, что на данный участок памяти больше нет ссылок, и очистит его.

Test(); void Test() < Person tom = new Person("Tom"); Console.WriteLine(tom.Name); >record class Person(string Name);

В методе Test создается объект Person. С помощью оператора new в куче для хранения объекта CLR выделяет участок памяти. А в стек добавляет адрес на этот участок памяти. В неявно определенном методе Main мы вызываем метод Test. И после того, как Test отработает, место в стеке очищается, а сборщик мусора очищает ранее выделенный под хранение объекта Person участок памяти.

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

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

Так же надо отметить, что для крупных объектов существует своя куча — Large Object Heap . В эту кучу помещаются объекты, размер которых больше 85 000 байт. Особенность этой кучи состоит в том, что при сборке мусора сжатие памяти не проводится по причине больших издержек, связанных с размером объектов.

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

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

К поколению 0 относятся новые объекты, которые еще ни разу не подвергались сборке мусора. К поколению 1 относятся объекты, которые пережили одну сборку, а к поколению 2 — объекты, прошедшие более одной сборки мусора.

Когда сборщик мусора приступает к работе, он сначала анализирует объекты из поколения 0. Те объекты, которые остаются актуальными после очистки, повышаются до поколения 1.

Если после обработки объектов поколения 0 все еще необходима дополнительная память, то сборщик мусора приступает к объектам из поколения 1. Те объекты, на которые уже нет ссылок, уничтожаются, а те, которые по-прежнему актуальны, повышаются до поколения 2.

Поскольку объекты из поколения 0 являются более молодыми и нередко находятся в адресном пространстве памяти рядом друг с другом, то их удаление проходит с наименьшими издержками.

Класс System.GC

Функционал сборщика мусора в библиотеке классов .NET представляет класс System.GC . Через статические методы данный класс позволяет обращаться к сборщику мусора. Как правило, надобность в применении этого класса отсутствует. Наиболее распространенным случаем его использования является сборка мусора при работе с неуправляемыми ресурсами, при интенсивном выделении больших объемов памяти, при которых необходимо такое же быстрое их освобождение.

Рассмотрим некоторые методы и свойства класса System.GC:

  • Метод AddMemoryPressure информирует среду CLR о выделении большого объема неуправляемой памяти, которую надо учесть при планировании сборки мусора. В связке с этим методом используется метод RemoveMemoryPressure , который указывает CLR, что ранее выделенная память освобождена, и ее не надо учитывать при сборке мусора.
  • Метод Collect приводит в действие механизм сборки мусора. Перегруженные версии метода позволяют указать поколение объектов, вплоть до которого надо произвести сборку мусора
  • Метод GetGeneration(Object) позволяет определить номер поколения, к которому относится переданый в качестве параметра объект
  • Метод GetTotalMemory возвращает объем памяти в байтах, которое занято в управляемой куче
  • Метод WaitForPendingFinalizers приостанавливает работу текущего потока до освобождения всех объектов, для которых производится сборка мусора

Работать с методами System.GC несложно:

// . long totalMemory = GC.GetTotalMemory(false); GC.Collect(); GC.WaitForPendingFinalizers(); //.

С помощью перегруженных версий метода GC.Collect можно выполнить более точную настройку сборки мусора. Так, его перегруженная версия принимает в качестве параметра число — номер поколения, вплоть до которого надо выполнить очистку. Например, GC.Collect(0) — удаляются только объекты поколения 0.

Еще одна перегруженная версия принимает еще и второй параметр — перечисление GCCollectionMode . Это перечисление может принимать три значения:

  • Default : значение по умолчанию для данного перечисления (Forced)
  • Forced : вызывает немедленное выполнение сборки мусора
  • Optimized : позволяет сборщику мусора определить, является ли текущий момент оптимальным для сборки мусора

Например, немедленная сборка мусора вплоть до первого поколения объектов: GC.Collect(1, GCCollectionMode.Forced);

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

Управление памятью в JavaScript выполняется автоматически и незаметно. Мы создаём примитивы, объекты, функции… Всё это занимает память.

Но что происходит, когда что-то больше не нужно? Как движок JavaScript обнаруживает, что пора очищать память?

Достижимость

Основной концепцией управления памятью в JavaScript является принцип достижимости.

Если упростить, то «достижимые» значения – это те, которые доступны или используются. Они гарантированно находятся в памяти.

  1. Существует базовое множество достижимых значений, которые не могут быть удалены. Например:
    • Выполняемая в данный момент функция, её локальные переменные и параметры.
    • Другие функции в текущей цепочке вложенных вызовов, их локальные переменные и параметры.
    • Глобальные переменные.
    • (некоторые другие внутренние значения)

Эти значения мы будем называть корнями.

В движке JavaScript есть фоновый процесс, который называется сборщиком мусора. Он отслеживает все объекты и удаляет те, которые стали недоступными.

Простой пример

Вот самый простой пример:

// в user находится ссылка на объект let user = < name: "John" >;

Здесь стрелка обозначает ссылку на объект. Глобальная переменная user ссылается на объект (мы будем называть его просто «John» для краткости). В свойстве «name» объекта John хранится примитив, поэтому оно нарисовано внутри объекта.

Если перезаписать значение user , то ссылка потеряется:

user = null;

Теперь объект John становится недостижимым. К нему нет доступа, на него нет ссылок. Сборщик мусора удалит эти данные и освободит память.

Две ссылки

Представим, что мы скопировали ссылку из user в admin :

// в user находится ссылка на объект let user = < name: "John" >; let admin = user;

Теперь, если мы сделаем то же самое:

user = null;

…то объект John всё ещё достижим через глобальную переменную admin , поэтому он находится в памяти. Если бы мы также перезаписали admin , то John был бы удалён.

Взаимосвязанные объекты

Теперь более сложный пример. Семья:

function marry(man, woman) < woman.husband = man; man.wife = woman; return < father: man, mother: woman >> let family = marry(< name: "John" >, < name: "Ann" >);

Функция marry «женит» два объекта, давая им ссылки друг на друга, и возвращает новый объект, содержащий ссылки на два предыдущих.

В результате получаем такую структуру памяти:

На данный момент все объекты достижимы.

Теперь удалим две ссылки:

delete family.father; delete family.mother.husband;

Недостаточно удалить только одну из этих двух ссылок, потому что все объекты останутся достижимыми.

Но если мы удалим обе, то увидим, что у объекта John больше нет входящих ссылок:

Исходящие ссылки не имеют значения. Только входящие ссылки могут сделать объект достижимым. Объект John теперь недостижим и будет удалён из памяти со всеми своими данными, которые также стали недоступны.

После сборки мусора:

Недостижимый «остров»

Вполне возможна ситуация, при которой целый «остров» взаимосвязанных объектов может стать недостижимым и удалиться из памяти.

Возьмём объект family из примера выше. А затем:

family = null;

Структура в памяти теперь станет такой:

Этот пример демонстрирует, насколько важна концепция достижимости.

Объекты John и Ann всё ещё связаны, оба имеют входящие ссылки, но этого недостаточно.

Бывший объект family был отсоединён от корня, на него больше нет ссылки, поэтому весь «остров» становится недостижимым и будет удалён.

Внутренние алгоритмы

Основной алгоритм сборки мусора называется «алгоритм пометок» (от англ. «mark-and-sweep»).

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

  • Сборщик мусора «помечает» (запоминает) все корневые объекты.
  • Затем он идёт по ним и «помечает» все ссылки из них.
  • Затем он идёт по отмеченным объектам и отмечает их ссылки. Все посещённые объекты запоминаются, чтобы в будущем не посещать один и тот же объект дважды.
  • …И так далее, пока не будут посещены все достижимые (из корней) ссылки.
  • Все непомеченные объекты удаляются.

Например, пусть наша структура объектов выглядит так:

Мы ясно видим «недостижимый остров» справа. Теперь давайте посмотрим, как будет работать «алгоритм пометок» сборщика мусора.

На первом шаге помечаются корни:

Затем помечаются объекты по их ссылкам:

…А затем объекты по их ссылкам и так далее, пока это возможно:

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

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

Это концепция того, как работает сборка мусора. Движки JavaScript применяют множество оптимизаций, чтобы она работала быстрее и не задерживала выполнение кода.

Вот некоторые из оптимизаций:

  • Сборка по поколениям (Generational collection) – объекты делятся на два набора: «новые» и «старые». В типичном коде многие объекты имеют короткую жизнь: они появляются, выполняют свою работу и быстро умирают, так что имеет смысл отслеживать новые объекты и, если это так, быстро очищать от них память. Те, которые выживают достаточно долго, становятся «старыми» и проверяются реже.
  • Инкрементальная сборка (Incremental collection) – если объектов много, и мы пытаемся обойти и пометить весь набор объектов сразу, это может занять некоторое время и привести к видимым задержкам в выполнении скрипта. Так что движок делит всё множество объектов на части, и далее очищает их одну за другой. Получается несколько небольших сборок мусора вместо одной всеобщей. Это требует дополнительного учёта для отслеживания изменений между частями, но зато получается много крошечных задержек вместо одной большой.
  • Сборка в свободное время (Idle-time collection) – чтобы уменьшить возможное влияние на производительность, сборщик мусора старается работать только во время простоя процессора.

Существуют и другие способы оптимизации и разновидности алгоритмов сборки мусора. Но как бы мне ни хотелось описать их здесь, я должен воздержаться, потому что разные движки реализуют разные хитрости и методы. И, что ещё более важно, все меняется по мере развития движков, поэтому изучать тему глубоко «заранее», без реальной необходимости, вероятно, не стоит. Если, конечно, это не вопрос чистого интереса, тогда для вас будет несколько ссылок ниже.

Итого

Главное, что нужно знать:

  • Сборка мусора выполняется автоматически. Мы не можем ускорить или предотвратить её.
  • Объекты сохраняются в памяти, пока они достижимы.
  • Если на объект есть ссылка – вовсе не факт, что он является достижимым (из корня): набор взаимосвязанных объектов может стать недоступен в целом, как мы видели в примере выше.

Современные движки реализуют разные продвинутые алгоритмы сборки мусора.

О многих из них рассказано в прекрасной книге о сборке мусора «The Garbage Collection Handbook: The Art of Automatic Memory Management» (R. Jones и др.).

Если вы знакомы с низкоуровневым программированием, то более подробная информация о сборщике мусора V8 находится в статье A tour of V8: Garbage Collection.

Также в блоге V8 время от времени публикуются статьи об изменениях в управлении памятью. Разумеется, чтобы изучить сборку мусора, вам лучше подготовиться, узнав о том как устроен движок V8 внутри в целом и почитав блог Вячеслава Егорова, одного из инженеров, разрабатывавших V8. Я говорю про «V8», потому что он лучше всего освещается в статьях в Интернете. Для других движков многие подходы схожи, но сборка мусора отличается во многих аспектах.

Глубокое понимание работы движков полезно, когда вам нужна низкоуровневая оптимизация. Было бы разумно запланировать их изучение как следующий шаг после того, как вы познакомитесь с языком.

Основы сборки мусора

В среде CLR сборщик мусора выполняет функции автоматического диспетчера памяти. Сборщик мусора управляет выделением и освобождением памяти для приложения. Поэтому разработчикам, работающим с управляемым кодом, не нужно писать код для выполнения задач управления памятью. Автоматическое управление памятью может устранить распространенные проблемы, такие как забыли освободить объект и вызвать утечку памяти или попытаться получить доступ к освобожденной памяти для уже освобожденного объекта.

В этой статье описаны основные понятия сборки мусора.

Льготы

Использование сборщика мусора обеспечивает следующие преимущества:

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

Основы работы с памятью

В следующем списке приведены важные понятия памяти СРЕДЫ CLR:

  • Каждый процесс имеет свое собственное отдельное виртуальное адресное пространство. Все процессы на одном компьютере используют одну и ту же физическую память и файл страницы, если есть один.
  • По умолчанию на 32-разрядных компьютерах каждому процессу выделяется 2 Гбайт виртуального адресного пространства в пользовательском режиме.
  • Разработчики приложений работают только с виртуальным адресным пространством и никогда не управляют физической памятью напрямую. Сборщик мусора выделяет и освобождает виртуальную память для разработчика в управляемой куче. При написании машинного кода для работы с виртуальным адресным пространством используются функции Windows. Эти функции выделяют и освобождают виртуальную память для разработчика в собственных кучах.
  • Виртуальная память может находиться в трех состояниях.

State Description
Бесплатно Ссылки на блок памяти отсутствуют, и он доступен для выделения.
Зарезервировано Блок памяти доступен для использования и не может использоваться для любого другого запроса на выделение. Однако вы не можете хранить данные в этом блоке памяти, пока не будет зафиксировано.
Зафиксировано Блок памяти назначен физическому хранилищу.

Выделение памяти

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

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

Освобождение памяти

Механизм оптимизации сборщика мусора определяет наилучшее время для выполнения сбора, основываясь на произведенных выделениях памяти. Когда сборщик мусора выполняет очистку, он освобождает память, выделенную для объектов, которые больше не используются приложением. Он определяет, какие объекты больше не используются, анализируя корни приложения. Корни приложения содержат статические поля, локальные переменные в стеке потока, регистры процессора, дескрипторы сборки мусора и очередь завершения. Каждый корень либо ссылается на объект, находящийся в управляемой куче, либо имеет значение NULL. Сборщик мусора может запросить остальную часть среды выполнения для этих корней. Сборщик мусора использует этот список для создания графа, содержащего все объекты, доступные из корней.

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

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

Для повышения производительности среда выполнения выделяет память для больших объектов в отдельной куче. Сборщик мусора автоматически освобождает память, выделенную для больших объектов. Но для устранения перемещений в памяти больших объектов эта память обычно не сжимается.

Условия для сборки мусора

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

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

Управляемая куча

После инициализации сборщика мусора среда CLR выделяет сегмент памяти для хранения объектов и управления ими. Эта память называется управляемой кучей в отличие от собственной кучи операционной системы.

Для каждого управляемого процесса существует управляемая куча. Все потоки в процессе выделяют память для объектов в одной и той же куче.

Для резервирования памяти сборщик мусора вызывает функцию Windows VirtualAlloc и резервирует для управляемых приложений по одному сегменту памяти за раз. Сборщик мусора также резервирует сегменты по мере необходимости и освобождает сегменты обратно в операционную систему (после очистки всех объектов), вызывая функцию Windows VirtualFree .

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

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

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

Степень вмешательства (частота и длительность) сборок мусора зависит от числа распределений и сохранившейся в управляемой куче памяти.

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

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

Поколения

Алгоритм сборки мусора учитывает следующее:

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

Сборка мусора в основном сводится к уничтожению короткоживущих объектов с небольшим временем жизни. Для оптимизации производительности сборщика мусора управляемая куча делится на три поколения: 0, 1 и 2. Следовательно, объекты с большим и небольшим временем жизни обрабатываются отдельно. Сборщик мусора хранит новые объекты в поколении 0. Уровень объектов, созданных на раннем этапе работы приложения и оставшихся после сборок мусора, повышается, и они сохраняются в поколении 1 и 2. Так как сжать часть управляемой кучи быстрее, чем всю кучу, эта схема позволяет сборщику мусора освобождать память в определенном поколении, а не для всей кучи при каждой сборке мусора.

  • Поколение 0: это поколение является самым молодым и содержит кратковременные объекты. Примером короткоживущего объекта является временная переменная. Сборка мусора чаще всего выполняется в этом поколении. Вновь распределенные объекты образуют новое поколение объектов и неявно являются сборками поколения 0. Тем не менее, если они являются большими объектами, они идут на кучу больших объектов (LOH), которая иногда называется поколением 3. Поколение 3 — это физическое поколение, которое логически собирается как часть поколения 2. Большинство объектов уничтожается при сборке мусора для поколения 0 и не доживает до следующего поколения. Если приложение пытается создать новый объект при заполнении поколения 0, сборщик мусора выполняет коллекцию, чтобы освободить адресное пространство для объекта. Сборщик мусора начинает проверять объекты в поколении 0, а не все объекты в управляемой куче. Сборка мусора только в поколении 0 зачастую освобождает достаточно памяти для того, чтобы приложение могло и дальше создавать новые объекты.
  • Поколение 1. Это поколение содержит короткие объекты и служит буфером между короткими объектами и долгосрочными объектами. Когда сборщик мусора выполняет сборку для поколения 0, память уплотняется для достижимых объектов и они продвигаются в поколение 1. Так как объекты, оставшиеся после сборки, обычно склонны к долгой жизни, имеет смысл продвинуть их в поколение более высокого уровня. Сборщику мусора необязательно выполнять повторную проверку объектов поколений 1 и 2 при каждой сборке мусора поколения 0. Если коллекция поколения 0 не освобождает достаточно памяти для создания нового объекта, сборщик мусора может выполнить коллекцию поколения 1, а затем поколение 2. Объекты в поколении 1, оставшиеся после сборок, продвигаются в поколение 2.
  • Поколение 2. Это поколение содержит долгосрочные объекты. Примером долгоживущих объектов служит объект в серверном приложении, содержащий статические данные, которые существуют в течение длительности процесса. Объекты поколения 2, которые сохраняют коллекцию, остаются в поколении 2, пока они не будут недоступны в будущей коллекции. Объекты в куче больших объектов (иногда называемой поколением 3) также собираются в поколении 2.

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

Выживание и переходы

Объекты, которые не были восстановлены в сборке мусора, известны как выжившие и повышены до следующего поколения:

  • Объекты, оставшиеся после сборки мусора поколения 0, подвигаются в поколение 1.
  • Объекты, оставшиеся после сборки мусора поколения 1, подвигаются в поколение 2.
  • Объекты, оставшиеся после сборки мусора поколения 2, остаются в поколении 2.

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

Эфемерные поколения и сегменты

Так как объекты в поколениях 0 и 1 являются короткоживущими, эти поколения называются эфемерными поколениями.

Эфемерные поколения выделяются в сегменте памяти, который называется эфемерным сегментом. Каждый новый сегмент, полученный сборщиком мусора, становится новым эфемерным сегментом и содержит объекты, пережившие сборку мусора для поколения 0. Старый эфемерный сегмент становится новым сегментом поколения 2.

Размер эфемерного сегмента зависит от того, является ли система 32-разрядной или 64-разрядной, а также от типа выполняемого сборщика мусора (рабочая станция или серверная сборка мусора). В следующей таблице показаны размеры по умолчанию для эфемерного сегмента:

Сборка мусора рабочей станции и сервера 32-разрядное 64-разрядное
Сборщик мусора рабочей станции 16 МБ 256 МБ
Сборщик мусора сервера 64 МБ 4 ГБ
GC сервера с > 4 логическими ЦП 32 МБ 2 ГБ
GC сервера с > 8 логическими ЦП 16 МБ 1 ГБ

Этот эфемерный сегмент может содержать объекты поколения 2. Объекты поколения 2 могут использовать несколько сегментов столько, сколько требуется для процесса, и память позволяет.

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

Процесс сборки мусора

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

  • Этап маркировки, выполняющий поиск всех используемых объектов и составляющий их перечень.
  • Этап перемещения, обновляющий ссылки на сжимаемые объекты.
  • Этап сжатия, освобождающий пространство, занятое неиспользуемыми объектами и сжимающий выжившие объекты. Этап сжатия перемещает объекты, которые пережили сборку мусора в сторону более старой части сегмента. Так как сборки поколения 2 могут занимать несколько сегментов, объекты, перешедшие в поколение 2, могут быть перемещены в более старый сегмент. Как поколение 1, так и 2 выживших можно переместить в другой сегмент, потому что они повышены до поколения 2. Обычно большая куча объектов (LOH) не сжимается, так как копирование больших объектов накладывает штраф за производительность. Однако в .NET Core и в .NET Framework 4.5.1 и более поздних версиях можно использовать свойство GCSettings.LargeObjectHeapCompactionMode для сжатия большой кучи объектов по требованию. Кроме того, куча больших объектов автоматически сжимается при установке жесткого ограничения с помощью одного из следующих параметров:
    • Предельный объем памяти для контейнера.
    • Параметры конфигурации среды выполнения GCHeapHardLimit или GCHeapHardLimitPercent .

    Чтобы определить, являются ли объекты используемыми, сборщик мусора задействует следующие сведения.

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

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

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

    Screenshot of how a thread triggers a Garbage Collection.

    Неуправляемые ресурсы

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

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

    Кроме того, нужно предусмотреть способ освобождения неуправляемых ресурсов в случае, если потребитель типа не вызовет Dispose . Вы можете использовать защищенный обработчик для создания оболочки для неуправляемого ресурса или переопределить метод Object.Finalize().

    См. также

    • Сборка мусора рабочей станции и сборка мусора сервера
    • Фоновая сборка мусора
    • Параметры конфигурации для сборки мусора
    • Сборка мусора

    Совместная работа с нами на GitHub

    Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *