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

Как устроена память в куче?

2.0 Middle🔥 113 комментариев
#Управление памятью

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

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

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

Устройство памяти в куче (Heap) в Unity/C#

Куча (Heap) — это область динамической памяти, управляемая сборщиком мусора (Garbage Collector, GC), где размещаются все ссылочные типы данных и boxed-значения. В отличие от стека, память в куче выделяется и освобождается не автоматически, а по запросу во время выполнения программы.

Основные принципы работы кучи в Unity

  1. Выделение памяти
    При создании объекта через new (например, new GameObject(), new List<int>()) память выделяется в куче. Система находит свободный блок подходящего размера и возвращает ссылку на него.

    // Пример: выделение памяти в куче
    GameObject player = new GameObject("Player"); // Объект размещается в куче
    List<Vector3> pathPoints = new List<Vector3>(); // Коллекция также в куче
    
  2. Сборка мусора (Garbage Collection)
    Unity использует generational GC (поколенческий сборщик мусора), который делит объекты в куче на три поколения:

    • Generation 0: недавно созданные объекты. Сборка здесь происходит часто и быстро.
    • Generation 1: объекты, пережившие одну сборку. Проверяются реже.
    • Generation 2: долгоживущие объекты (например, синглтоны, загруженные ассеты). Сборка здесь наиболее затратна.

    Когда куча заполняется, GC приостанавливает выполнение программы (stop-the-world), находит недостижимые объекты (на которые нет ссылок) и освобождает память.

  3. Фрагментация кучи
    Постоянное создание и удаление объектов разного размера приводит к фрагментации — между блоками памяти возникают "дыры", которые невозможно использовать для больших объектов. Это может вызвать неожиданные аллокации и срабатывания GC.

Ключевые особенности кучи в Unity

  • Производительность: аллокации в куче медленнее, чем в стеке, из-за поиска свободного блока и возможной фрагментации.
  • Управление памятью: разработчик должен минимизировать частые аллокации, особенно в Update(), чтобы избежать просадок FPS.
  • Ссылочная семантика: объекты в куче передаются по ссылке, а не по значению.

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

  • Избегайте аллокаций в игровом цикле: кэшируйте компоненты, используйте пулы объектов для часто создаваемых/удаляемых сущностей (пули, враги, эффекты).

    // Плохо: аллокация в Update()
    void Update() {
        List<Enemy> enemies = new List<Enemy>(); // Аллокация каждый кадр!
    }
    
    // Хорошо: переиспользование коллекции
    private List<Enemy> _enemiesCache = new List<Enemy>();
    void Update() {
        _enemiesCache.Clear(); // Без аллокаций
        // ... работа с кэшем
    }
    
  • Используйте структуры для легковесных данных: если объект мал и короткоживущ, предпочитайте структуру (value type), которая размещается в стеке (например, Vector3, RaycastHit).

  • Контролируйте ссылки: явно обнуляйте ссылки (null), когда объект больше не нужен, чтобы ускорить его очистку GC.

  • Профилируйте память: регулярно используйте Unity Profiler (окно Memory) для отслеживания утечек, фрагментации и неожиданных аллокаций.

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

Неконтролируемая работа с кучей — частая причина лагов в играх на Unity. Например, если в кадре аллоцируются десятки мегабайт, GC будет вынужден часто запускаться, вызывая задержки до 100+ мс. Оптимизация сводится к:

  • Снижению количества аллокаций.
  • Уменьшению размера создаваемых объектов.
  • Использованию struct вместо class там, где это уместно.

Понимание устройства кучи критически важно для создания плавного игрового процесса, особенно на мобильных платформах с ограниченной памятью.

Как устроена память в куче? | PrepBro