← Назад к вопросам

Как запускается Garbage Collection?

2.3 Middle🔥 192 комментариев
#Память и Garbage Collector

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Общий механизм запуска сборки мусора (Garbage Collection)

В .NET Garbage Collection (GC) — это автоматический процесс управления памятью, который освобождает объекты, более не используемые приложением. GC работает на основе трех поколений (Generation 0, 1, 2) и может запускаться по нескольким условиям, в зависимости от реализации (Workstation или Server GC).

Условия запуска GC

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

1. Выделение памяти в Generation 0

При создании нового объекта в управляемой куче (heap), если для Generation 0 недостаточно памяти, происходит сборка мусора. Это самый частый сценарий.

// Пример: массовое создание объектов может спровоцировать GC
for (int i = 0; i < 100000; i++)
{
    var obj = new MyClass(); // Если память Gen0 заполнена — запускается GC
}

2. Явный вызов GC.Collect()

Разработчик может программно инициировать сборку, но это рекомендуется только в специфичных сценариях (например, при падении памяти в долгоживущих приложениях).

// Принудительная полная сборка (все поколения)
GC.Collect();
// Ожидание завершения финализаторов (опционально)
GC.WaitForPendingFinalizers();

3. Нехватка системной памяти

Операционная система может сигнализировать о высоком давлении на память, что вызывает полную сборку (Generation 2).

4. Выгрузка домена приложения (AppDomain)

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

5. Срабатывание финализаторов (Finalization Queue)

Если очередь финализаторов переполнена, GC может запуститься для их обработки.

Типы сборок: эфемерная (Ephemeral) и полная (Full)

Эфемерная сборка

Затрагивает только Generation 0 (иногда и Generation 1). Быстрая, происходит часто.

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

Полная сборка (Gen2)

Затрагивает все поколения, более ресурсоемкая.

  • Алгоритм: уплотняющий (compacting), чтобы избежать фрагментации.
  • Типы кучи:
    • Small Object Heap (SOH) – объекты < 85 КБ.
    • Large Object Heap (LOH) – объекты ≥ 85 КБ (собирается только при полной сборке).

Управление поведением GC

Режимы работы GC

// Конфигурация в .csproj или runtimeconfig.json
// Workstation GC (по умолчанию для клиентских приложений)
<PropertyGroup>
  <ServerGarbageCollection>false</ServerGarbageCollection>
</PropertyGroup>

// Server GC (для серверных приложений, выделяет отдельные кучи на ядро CPU)
<PropertyGroup>
  <ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>

Фоновые (Background) и неблокирующие сборки

  • Background GC (включен по умолчанию с .NET 4.0): сборка Gen2 выполняется в фоновом потоке, не блокируя рабочие потоки.
  • Foreground GC: блокирует все управляемые потоки (редкий случай при нехватке памяти).

Критические практики и рекомендации

  1. Избегайте явных вызовов GC.Collect() – это нарушает оптимизации и может ухудшить производительность.
  2. Используйте using для IDisposable – гарантирует своевременное освобождение неуправляемых ресурсов.
  3. Осторожно с финализаторами – они продлевают жизнь объектов, добавляя их в Finalization Queue.
  4. Мониторинг через Performance Counters или события GC:
// Подписка на уведомления о нехватке памяти
GC.RegisterForFullGCNotification(10, 10);
Task.Run(() =>
{
    while (true)
    {
        if (GC.WaitForFullGCApproach() == GCNotificationStatus.Succeeded)
        {
            // Принять меры перед сборкой
        }
    }
});

Влияние на производительность

  • Латентность: полная сборка может вызывать паузы (STW — Stop-The-World).
  • Оптимизация: уменьшение количества ссылочных объектов, использование структур (value types), пулинг объектов (ArrayPool, MemoryPool).
  • Диагностика: инструменты вроде PerfView, dotnet-counters, Visual Studio Diagnostic Tools.

Итог: GC в .NET — высокооптимизированная система, которая самостоятельно определяет оптимальные моменты для запуска. Понимание ее работы позволяет писать эффективный код, минимизирующий ненужные сборки и "утечки" памяти (когда объекты не освобождаются из-за оставшихся ссылок).