Сколько поколений (generations) имеет управляемая куча в .NET?

«Сколько поколений (generations) имеет управляемая куча в .NET?» — вопрос из категории Управление памятью, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Сборщик мусора (GC) в .NET использует три поколения для организации управляемой кучи (Managed Heap): Gen 0, Gen 1 и Gen 2. Эта модель, называемая поколенческой (generational), основана на эмпирическом наблюдении, что большинство объектов живут недолго (гипотеза слабого поколения).

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

Отдельно существует Куча больших объектов (Large Object Heap — LOH), куда помещаются объекты размером ≥ 85 000 байт (≈85 КБ). LOH собирается только во время сборки Gen 2 и не подвергается уплотнению (compaction) по умолчанию, что может приводить к фрагментации.

// Пример, демонстрирующий поколение объекта
var obj = new object();
Console.WriteLine(GC.GetGeneration(obj)); // Скорее всего выведет 0

// Принудительная сборка мусора только для Gen 0 и Gen 1
GC.Collect(1);
// После выживания в сборке, поколение объекта увеличится
Console.WriteLine(GC.GetGeneration(obj)); // Может вывести 1 или 2