Последние несколько лет я много писал серверного кода на dotnet, и меня постоянно радовала скорость итерации.
Делаешь изменение — почти моментально получаешь отклик. В Unity это всегда боль.
Я постоянно стараюсь работать так, чтобы как можно реже триггерить Domain Reload.
Эта штука на каждое, даже мелкое изменение отнимает десятки секунд.
Если взять обычный день и просто посчитать время на ожидание — легко набегут десятки минут.
🔸Почему так происходит?
Редактор Unity на всех платформах работает на Mono — старом кроссплатформенном runtime. В его основе лежит JIT-компиляция.
Когда вызывается твой метод первый раз, туда прописан вызов JIT-компилятора.
Он берёт IL-код метода, конвертирует в Mono IR (внутреннее представление Mono), оптимизирует, и только после этого генерирует инструкции для конкретного процессора.
Казалось бы, при чём тут мы? А при том, что Mono JIT — операция не бесплатная. И в редакторе она обходится очень дорого.
🔸Domain Reload
Его порядок работы примерно такой:
1️⃣ Находим все MonoBehaviour и вызываем OnDisable/OnDestroy
2⃣ Выгружаем все *.dll движка и наши
3⃣ Освобождаем GC Handles и выгружаем Domain
4⃣ Создаём новый Domain и загружаем все *.dll движка
5⃣ Загружаем все *.dll игрока
6⃣ Запускаем скрипты с [InitializeOnLoad]
7⃣ На пересозданных MonoBehaviour вызываем Awake/OnEnable
На моём проекте Magic Battle Arena (~100к строк кода, 149 сборок) эти 7 пунктов занимают 12 секунд.
Угадайте какая операция самая долгая?
Mono JIT — примерно 5.5 секунд в сумме.
Это происходит потому, что мы вынуждены полностью выгрузить ВСЕ *.dll (для которых методы уже скомпилированы) и перекомпилировать их заново.
🔸Почему это нельзя исправить в Mono
Проблема фундаментальная. В Mono нет механизма hot swap для сборок. Нельзя сказать "выгрузи только эту dll и загрузи новую версию".
Только полная перезагрузка домена.
CoreCLR решает это через AssemblyLoadContext, см. прошлый пост
🔸RyuJIT vs Mono JIT
Но даже если Unity не реализует hot reload, сам JIT-компилятор CoreCLR (RyuJIT) работает иначе.
Mono JIT — однопроходный. Скомпилировал метод один раз — живи с этим. Хочешь лучше? Используй AOT.
RyuJIT поддерживает Tiered Compilation:
🔹Tier 0: быстрая компиляция без оптимизаций (для быстрого старта)
🔹Tier 1: метод был вызван более 30 раз и более? — Оптимизируем его
Т.е. при Domain Reload методы сначала компилируются максимально быстро, а потом в фоне докомпилируются с оптимизациями.
Время ожидания сокращается, performance не страдает.
Но выиграем мы от смены JIT компилятора, я уверен не так много, как c перехода с Domain Reload на Code Reload.
🔻Мой прогноз:
Время Domain Reload снизится минимум на 75%.
В моём примере — с 12 секунд до 3. Останутся только вызовы Awake/Destroy и десериализация состояния сцен.
Проверим в
Теперь ты знаешь что загадать на Новый Год 😊
Ставь 👍 если тебе заходит такого рода контент!
Ты знаешь кому переслать эту статью 💪
#unite2025@UniArchitect
#проект_в_разработке@UniArchitect
