Ответ
Явный вызов сборщика мусора выполняется с помощью статического метода GC.Collect(). Однако, это почти всегда антипаттерн в production-коде. Сборщик мусора в .NET — высокооптимизированный компонент, и ручные вызовы обычно ухудшают производительность.
Синтаксис вызова:
// Простой вызов сборки для поколения 0 и 1 (реже 2)
GC.Collect();
// Вызов для конкретного поколения (0, 1, 2)
GC.Collect(2); // Принудительная полная сборка
// Рекомендуемый паттерн для сценариев с финализаторами:
// 1. Запуск сборки
GC.Collect();
// 2. Ожидание завершения финализаторов для собранных объектов
GC.WaitForPendingFinalizers();
// 3. Ещё одна сборка, чтобы очистить память от самих финализированных объектов
GC.Collect();
Когда это может быть оправдано (с большой осторожностью):
- Профилирование и тестирование: Например, чтобы измерить "чистое" потребление памяти после выполнения определённого блока кода.
long before = GC.GetTotalMemory(false); // ... выполнение исследуемого кода ... GC.Collect(); // Принудительная уборка для точного замера GC.WaitForPendingFinalizers(); long after = GC.GetTotalMemory(true); Console.WriteLine($"Used memory: {after - before} bytes"); - Сценарии с большими, чётко ограниченными временными интервалами: Например, в симуляциях или графических редакторах, где есть явная "пауза" (например, между уровнями игры), и нужно гарантированно освободить память перед следующей ресурсоёмкой операцией.
Почему обычно не нужно вызывать GC.Collect():
- Нарушение эвристик GC: GC сам определяет оптимальный момент для сборки, основываясь на выделении памяти и фрагментации. Ручные вызовы сбивают эти алгоритмы.
- Снижение производительности: Полная сборка мусора (особенно поколения 2) — дорогая операция, "останавливающая мир" (stop-the-world).
- Маскировка реальных проблем: Частая потребность в ручной сборке часто указывает на проблемы в архитектуре, такие как утечки памяти (особенно из-за неправильных подписок на события, кэшей без ограничений) или чрезмерное выделение памяти в "горячих" путях (аллокации в циклах).
Правильный подход: Вместо ручного вызова GC сфокусируйтесь на:
- Использовании
usingдляIDisposableобъектов. - Избегании долгоживущих ссылок на короткоживущие объекты.
- Профилировании памяти с помощью инструментов (dotMemory, Visual Studio Diagnostic Tools) для поиска реальных утечек.