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

Как можно чистить мусор без Garbage collector?

2.8 Senior🔥 232 комментариев
#Оптимизация

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

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

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

Стратегии управления памятью без активного GC в Unity

Для минимизации или полного избегания сборок мусора (Garbage Collection, GC) в Unity требуется переход от управления памятью по ссылкам к предсказуемому ручному управлению или использованию структур без аллокаций. Вот ключевые подходы:

1. Использование значимых типов (Value Types) вместо ссылочных

Замена классов на структуры (struct) предотвращает аллокации в управляемой куче. Однако это не всегда подходит для сложных объектов.

public struct DamageInfo // Структура вместо класса
{
    public int Amount;
    public DamageType Type;
}
// Использование: аллокация на стеке, нет нагрузки на GC

2. Пул объектов (Object Pooling)

Самый распространённый метод для переиспользования объектов вместо их создания и уничтожения.

public class GameObjectPool
{
    private Queue<GameObject> _pool = new Queue<GameObject>();
    
    public GameObject Get(Vector3 position)
    {
        if (_pool.Count > 0)
        {
            var obj = _pool.Dequeue();
            obj.transform.position = position;
            obj.SetActive(true);
            return obj;
        }
        return InstantiateNewObject(position);
    }
    
    public void Return(GameObject obj)
    {
        obj.SetActive(false);
        _pool.Enqueue(obj); // Возврат в пул, а не Destroy
    }
}

3. Предварительное выделение массивов и использование ArrayPool

Использование статических массивов или System.Buffers.ArrayPool<T> для переиспользования массивов без аллокаций.

using System.Buffers;
// Использование пула массивов
var rentedArray = ArrayPool<int>.Shared.Rent(minimumLength);
// ... операции с массивом
ArrayPool<int>.Shared.Return(rentedArray);

4. Структуры данных без аллокаций

  • Системные типы: Использование System.Span<T> и System.Memory<T> для работы с памятью без дополнительных выделений.
  • Неизменяемые коллекции: Предварительная инициализация коллекций с достаточной ёмкостью (List.Capacity) для предотвращения реаллокаций.

5. Кэширование делегатов и событий

Создание делегатов и подписка на события часто генерируют мусор. Решение — кэширование:

private Action _cachedAction; // Кэшированный делегат

void Start()
{
    _cachedAction = HandleEvent;
    someObject.OnEvent += _cachedAction; // Одна аллокация вместо множества
}

6. Использование unsafe кода и указателей (в редких случаях)

В performance-critical участках можно использовать небезопасный код для прямого управления памятью:

unsafe void ProcessData(int* array, int length)
{
    // Работа с указателями без контроля GC
    // Требует Compiler AllowUnsafeBlocks
}

7. Статические классы и синглтоны

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

8. Избегание Boxing при работе с типами значений

Boxing (упаковка) при приведении структур к `object` или интерфейсам создаёт мусор:
int value = 42;
object boxed = value; // Boxing — аллокация в куче!
// Вместо этого используйте generics или специализированные методы

Практические рекомендации для Unity

  1. Профилирование: Используйте Unity Profiler (с включённой детализацией GC) для поиска источников аллокаций.
  2. Update-методы: Особое внимание уделите коду в Update(), FixedUpdate() — даже мелкие аллокации здесь накапливаются.
  3. Строки (String): Конкатенация строк в циклах создаёт мусор. Используйте StringBuilder, string.Format() или кэширование.
  4. LINQ и анонимные методы: Часто генерируют скрытые аллокации. В performance-critical коде избегайте их или используйте с осторожностью.

Важные ограничения

  • Полное отключение GC невозможно в управляемой среде C#. Речь идёт только о сведении к нулю рутинных аллокаций.
  • Unity использует Boehm–Demers–Weiser garbage collector (для IL2CPP — модифицированный Boehm), который нельзя «отключить».
  • Даже при нулевых аллокациях фоновые процессы .NET/Unity могут создавать минимальный мусор.
  • На мобильных платформах (особенно iOS/Android) контроль памяти критически важен из-за ограниченных ресурсов.

Заключение

«Очистка мусора без GC» на практике означает проектирование без его генерации. Это требует дисциплины, использования пулов, value-типов и профилирования. В реальных проектах достигают показателей 0B аллокаций в основном игровом цикле, что полностью предотвращает периодические просадки FPS от сборок мусора. Однако для одноразовой инициализации или загрузки аллокации допустимы. Главное — баланс между производительностью и поддерживаемостью кода.

Как можно чистить мусор без Garbage collector? | PrepBro