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

Что такое сборка мусора?

1.2 Junior🔥 212 комментариев
#Оптимизация#Управление памятью

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

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

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

Что такое сборка мусора (Garbage Collection, GC)?

Сборка мусора — это автоматический процесс управления памятью, который освобождает память, занятую объектами, которые больше не используются программой. В контексте Unity и C# (который использует .NET платформу) сборка мусора является ключевым механизмом, позволяющим разработчикам не отслеживать вручную время жизни каждого объекта в динамической памяти (куче).

Как это работает в Unity (C#)?

Процесс можно разделить на несколько этапов:

  1. Выделение памяти. Когда вы создаете новый объект с помощью оператора new, память для него выделяется в управляемой куче (managed heap). Пока есть свободное место, это происходит очень быстро.

    // Пример создания объекта, который попадет в управляемую кучу
    GameObject projectile = new GameObject("Projectile");
    Enemy enemyInstance = new Enemy();
    
  2. Отслеживание ссылок. Среда выполнения .NET (CLR) отслеживает все активные ссылки на объекты в куче. Если на объект больше не ссылается ни одна переменная в коде (корневая ссылка), он считается "мусором" (garbage).

  3. Собственно сборка. Периодически (или при определенных условиях) сборщик мусора (Garbage Collector) запускается, чтобы:

    *   **Пометить** все недостижимые объекты.
    *   **Освободить** память, занятую этими объектами (финальные деструкторы могут быть вызваны в этот момент).
    *   **Уплотнить** кучу (переместить оставшиеся живые объекты в начало, чтобы избежать фрагментации и увеличить свободное непрерывное пространство).

Почему это важно в разработке игр на Unity?

Несмотря на автоматизацию, GC не является "бесплатным" и может негативно повлиять на производительность игры:

  • Просадки производительности (фризы). Сам процесс сборки мусора требует вычислительных ресурсов и обычно останавливает все потоки выполнения на время работы (в стандартной реализации). Если в куче накопилось много мусора, этот стоп может длиться десятки миллисекунд, что приводит к заметным "фризам" или "тормозам" во время геймплея.
  • Непредсказуемость. Точный момент запуска GC детерминированно не контролируется разработчиком (хотя его можно инициировать принудительно). В пиковые моменты игры (нагрузка в бою, генерация уровня) это может привести к катастрофическому падению FPS.

Основные методы оптимизации GC в Unity

Для создания плавного игрового процесса разработчики активно борются с частыми или долгими сборками мусора:

  1. Пулы объектов (Object Pooling). Вместо постоянного создания и уничтожения объектов (например, пуль, врагов, эффектов) используется заранее созданный пул. Объекты при "уничтожении" деактивируются и возвращаются в пул, а при необходимости — берутся из него. Это полностью исключает аллокации и последующий мусор для часто используемых объектов.

    // Упрощенная концепция пула
    public class ProjectilePool : MonoBehaviour {
        public GameObject projectilePrefab;
        private Queue<GameObject> pool = new Queue<GameObject>();
    
        public GameObject GetProjectile() {
            if (pool.Count > 0) {
                GameObject obj = pool.Dequeue();
                obj.SetActive(true);
                return obj;
            }
            return Instantiate(projectilePrefab);
        }
    
        public void ReturnProjectile(GameObject obj) {
            obj.SetActive(false);
            pool.Enqueue(obj);
        }
    }
    
  2. Структуры вместо классов для мелких данных. Значимые типы (struct) хранятся в стеке (или внутри родительского объекта в куче) и уничтожаются немедленно при выходе из области видимости, не нагружая кучу и GC. Но важно помнить о семантике копирования структур.

    // Vector3 в Unity — это структура (struct), поэтому его использование не создает мусор.
    void Update() {
        Vector3 newPosition = transform.position + Vector3.forward * Time.deltaTime; // Аллокации в куче нет
    }
    
  3. Контроль над частыми аллокациями.

    *   Избегать выделения памяти в часто вызываемых методах (`Update`, `FixedUpdate`).
    *   Кэшировать ссылки на компоненты и объекты, а не искать их каждый кадр через `GetComponent<>()` или `Find()`.
    *   Использовать `StringBuilder` для динамического формирования строк вместо множественных конкатенаций (`string + string`).
    *   При работе с массивами данных использовать неуправляемые коллекции (например, `NativeArray`) в рамках **Unity Data-Oriented Technology Stack (DOTS)**, которые обходят стандартный GC.

  1. Принудительный вызов GC. В редких случаях, в моменты простоя (например, загрузка уровня, меню паузы), можно вызвать System.GC.Collect(), чтобы провести сборку в "удобный" момент и снизить вероятность ее запуска в критический для FPS момент. Однако злоупотреблять этим не стоит.

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