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

Есть ли Large Object Heap в Unity?

3.0 Senior🔥 141 комментариев
#Управление памятью

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

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

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

Наличие Large Object Heap (LOH) в Unity

Да, Large Object Heap (LOH) полностью присутствует и активно влияет на работу приложений, собранных под платформу .NET (в первую очередь, Windows Standalone и иногда под другие платформы, использующие Mono или IL2CPP с .NET runtime). Это фундаментальная часть системы управления памятью в среде выполнения .NET, на которой построена Unity. Однако его влияние и видимость для разработчика сильно зависят от версии Unity, используемого скриптового бэкенда (Mono vs IL2CPP) и целевой платформы.

Как LOH работает в контексте Unity

LOH — это специальная область управляемой кучи (managed heap) в .NET, предназначенная для хранения объектов очень большого размера (по умолчанию 85 000 байт и более). Основная особенность LOH в том, что сборщик мусора (Garbage Collector, GC) не перемещает объекты в этой области для их компактирования. Это приводит к двум ключевым последствиям:

  1. Снижение нагрузки на GC: Избегаются затраты на копирование больших блоков памяти.
  2. Фрагментация памяти: После освобождения больших объектов на LOH остаются "дыры", которые может быть сложно заполнить новыми большими объектами, что ведет к неэффективному использованию памяти и потенциальному росту потребления памяти (memory footprint) приложения.

Что в Unity обычно попадает в LOH?

В Unity разработчик редко создает настолько большие управляемые объекты напрямую. Чаще всего в LOH попадают внутренние структуры данных, создаваемые самим движком или стандартными библиотеками .NET:

  • Большие массивы (byte[], float[], Vector3[]): Самый частый источник проблем.
    // Этот массив почти наверняка окажется в LOH
    byte[] hugeTextureData = new byte[100_000]; // 100КБ > 85КБ порог
    
  • Строки (string) большой длины: Строки в .NET — неизменяемые массивы символов.
  • Списки (List<T>) и другие коллекции, если их внутренний буфер превышает порог.
  • Массивы мешей: При работе с очень детализированными мешами (Mesh.vertices, Mesh.triangles) их данные, сериализованные в управляемые массивы, могут легко превысить лимит.
  • Данные AssetBundle или другие бинарные блобы, загружаемые в память в виде массивов байт.

Практические проблемы и решения для Unity-разработчика

Попадание объектов в LOH становится проблемой, когда вызывает:

  • Неожиданные паузы GC: Хотя сборка LOH происходит реже (часто только при полной сборке поколения 2), она может быть длительной.
  • Утечки памяти (фрагментация): Даже после освобождения ссылок на большие объекты, память в процессе может не возвращаться системе, что видно в профайлере как высокий Managed Heap Used.
  • OutOfMemoryException из-за невозможности найти непрерывный блок нужного размера в Lрагментированной LOH.

Стратегии минимизации влияния LOH:

  1. Избегайте создания больших управляемых массивов. Вместо byte[] для работы с текстурами или сетевыми пакетами используйте нативные (NativeArray<T>, NativeSlice<T>) или unsafe-буферы, которые живут вне управляемой кучи.

    using Unity.Collections;
    NativeArray<byte> nativeData = new NativeArray<byte>(100_000, Allocator.Persistent);
    // Работа с данными...
    nativeData.Dispose(); // Явное освобождение
    
  2. Разбивайте данные на чанки. Если нужен большой логический набор данных, храните его как список массивов размером меньше 85КБ.

    List<byte[]> chunkedData = new List<byte[]>();
    const int CHUNK_SIZE = 80000; // Меньше порога LOH
    for (int i = 0; i < totalSize; i += CHUNK_SIZE) {
        chunkedData.Add(new byte[Mathf.Min(CHUNK_SIZE, totalSize - i)]);
    }
    
  3. Активно используйте пуллинг (object pooling) для больших объектов. Не создавайте и не уничтожайте большие массивы каждый кадр. Выделите их один раз и переиспользуйте.

    public class LargeArrayPool {
        private static Queue<byte[]> pool = new Queue<byte[]>();
        public static byte[] Get(int size) {
            // Логика поиска подходящего массива в пуле...
        }
        public static void Return(byte[] array) {
            // Очистка и возврат в очередь...
        }
    }
    
  4. Внимательно анализируйте Profiler. В окне Memory Profiler (глубокий режим) можно отследить размер управляемой кучи и выделить конкретные объекты, которые в ней находятся. Инструменты вроде Unity Heap Explorer или dotMemory от JetBrains помогают детально анализировать LOH.

  5. Учитывайте целевые платформы. На iOS/Android под IL2CPP поведение может отличаться, но большие управляемые массивы все равно остаются источником проблем с производительностью GC, даже если механизм LOH реализован иначе.

Вывод: Large Object Heap — это не миф, а реальность в экосистеме Unity. Прямого API для управления им в Unity нет, так как это особенность рантайма .NET. Ключевая задача разработчика — осознанно управлять памятью, избегая частого аллокирования больших управляемых объектов, и использовать современные инструменты Unity (нативные коллекции, Job System, Burst compiler) для работы с большими объемами данных вне управляемой кучи, где это возможно. Это критически важно для поддержания стабильной частоты кадров, особенно на мобильных и VR-платформах.

Есть ли Large Object Heap в Unity? | PrepBro