Сборщик мусора (GC) — это ключевой компонент CLR (Common Language Runtime), который автоматически управляет памятью в .NET приложениях. Вот как это работает:
1. Основные принципы работы GC
- Автоматическое управление памятью: Разработчик не освобождает память вручную
- Поколения (Generations): Объекты разделены на 3 поколения (0, 1, 2)
- Триггеры сборки: GC запускается при недостатке памяти или по другим условиям
2. Организация памяти
Управляемая куча (Managed Heap) делится на:
- Поколение 0: Новые объекты (малый размер, ```256KB-4MB)
- Поколение 1: "Буфер" между поколениями 0 и 2 (```2MB-16MB)
- Поколение 2: Долгоживущие объекты (```10MB-несколько GB)
- Large Object Heap (LOH): Объекты >85KB (не поколенческий)
// Пример, показывающий поколение объекта
var obj = new object();
Console.WriteLine(GC.GetGeneration(obj)); // Выведет 0 (поколение)
3. Алгоритм работы GC
Фаза маркировки
- GC приостанавливает все потоки приложения
- Строит граф достижимых объектов, начиная с корней (корни — это статические поля, локальные переменные и регистры CPU)
- Помечает все достижимые объекты
Фаза очистки
- Освобождает память недостижимых объектов
- Для достижимых объектов обновляет указатели (при компактификации)
Фаза компактификации
- Перемещает живые объекты для устранения фрагментации
- Обновляет все ссылки на перемещенные объекты
4. Типы сборок мусора
- Полная сборка (Full GC): Обрабатывает все поколения (Gen 0, 1, 2 + LOH)
- Эфемерная сборка (Ephemeral GC): Только Gen 0 и Gen 1
- Фоновая сборка (Background GC): Параллельная сборка для Gen 0 и 1 во время Full GC (только для Workstation GC)
5. Режимы работы GC
- Workstation GC: Оптимизирован для клиентских приложений (меньшие задержки)
- Server GC: Оптимизирован для серверных приложений (выделяет кучу и GC на каждый CPU core)
// Настройка режима GC в конфигурации
<configuration>
<runtime>
<gcServer enabled="true"/> <!-- Server GC -->
<gcConcurrent enabled="false"/> <!-- Отключаем фоновый GC -->
</runtime>
</configuration>
6. Финализаторы и Dispose
- Объекты с финализаторами попадают в очередь финализации
- Требуют минимум двух проходов GC для полного освобождения
- Паттерн Dispose: Рекомендуется для освобождения неуправляемых ресурсов
// Правильная реализация Dispose
public class Resource : IDisposable {
private bool disposed = false;
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if(!disposed) {
if(disposing) {
// Освобождаем управляемые ресурсы
}
// Освобождаем неуправляемые ресурсы
disposed = true;
}
}
```Resource() {
Dispose(false);
}
}
7. Оптимизации GC
- Сегменты памяти: GC работает с сегментами, а не со всей кучей сразу
- Фоновый сборщик (Background GC): Позволяет работать потокам во время сборки Gen 2
- Pinned objects: Закрепленные объекты (через fixed) не перемещаются, что может приводить к фрагментации
8. Методы управления GC
GC.Collect()
: Принудительный запуск сборки (обычно не рекомендуется)
GC.WaitForPendingFinalizers()
: Ожидание завершения финализаторов
GC.GetTotalMemory()
: Получение информации об использованной памяти
GC.AddMemoryPressure()
: Уведомление GC о большом неуправляемом потреблении памяти
Резюмируем:
Сборщик мусора в .NET — это сложная, высокооптимизированная система автоматического управления памятью, использующая поколения объектов, различные стратегии сборки и работающая в тесной интеграции с CLR. Понимание его работы критически важно для написания эффективных и надежных .NET-приложений, особенно при работе с большими объемами данных или в высоконагруженных сценариях.