Перейти к основному содержимому

Native AOT в .NET

Разработчику Архитектору

Native AOT (Ahead-of-Time) — режим публикации, при котором приложение компилируется в нативный исполняемый файл до запуска. Обычный .NET при старте использует JIT (Just-In-Time) — компилятор превращает IL в машинный код уже во время работы программы.

Обзор цепочки IL → CLR → JIT — Платформа .NET, архитектура. Таблица версий — 48. Сборка и деплой — 14.


Словарь

ТерминЗначение
IL (Intermediate Language)Промежуточный байт-код .NET после компиляции C#.
JITКомпиляция IL в машинный код при запуске.
AOTКомпиляция в машинный код до запуска.
TrimmingУдаление неиспользуемого кода из сборки при публикации.
РефлексияЧтение метаданных типов в runtime (typeof, GetProperty).
Cold startВремя от старта процесса до первого полезного ответа.

Когда Native AOT уместен

СценарийAOT
CLI-утилита, cron, sidecarОбычно да
Serverless с жёстким cold startОбычно да
IoT, контейнер с малым RAMОбычно да
Крупный ASP.NET + EF + SwaggerЧасто нет на текущем этапе
Плагины из DLL в runtimeНет

ReadyToRun (R2R) — промежуточный вариант: IL + частично готовый нативный код, JIT остаётся. Сравнение — 14.


Минимальный проект

Файл MyTool.csproj:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
</Project>

Публикация:

dotnet publish -c Release -r linux-x64 --self-contained

На выходе — бинарник, который можно запустить без установленного .NET на машине (self-contained).

InvariantGlobalization уменьшает размер, если приложению не нужны локали всех культур.


Ограничения

ВозможностьВ Native AOT
Reflection.Emit, динамические сборкиНедоступно
Рефлексия без аннотацийМожет быть вырезана trimmer
Newtonsoft.Json без source generatorЧасто проблемно
Expression.Compile()Ограничено
Загрузка плагинов из произвольных DLLПрактически нет

Что помогает

  • Source generators для JSON (System.Text.Json + JsonSerializerContext)
  • Явные контракты DI без рефлексии "по имени"
  • Минимум динамической генерации кода

Trimming и анализаторы

При AOT и trim анализатор предупреждает о коде, который зависит от рефлексии, но не помечен для сохранения.

  • DynamicallyAccessedMembers — подсказка компилятору, какие члены типа нужны.
  • RequiresUnreferencedCode — пометка API, несовместимого с trimming.

Тестируйте опубликованный артефакт (dotnet publish), а не только dotnet run в Debug — ошибки часто проявляются только после trim.


ASP.NET Core и AOT

С .NET 8+ поддержка AOT для части стека ASP.NET расширяется, но не всё из экосистемы NuGet совместимо.

Перед выбором AOT для веб-приложения:

  1. Прочитайте документацию Microsoft для вашей версии SDK.
  2. Проверьте зависимости на совместимость.
  3. Для типичного LOB API с EF чаще достаточно обычного publish в контейнер — контейнеризация.

CLI и edge-сценарии — выбор архитектуры.


Схема выбора


Частые ошибки

  • Тест только в Debug — AOT-ошибки в Release/publish.
  • Игнорирование trim warnings — MissingMethodException в продакшене.
  • AOT без измеримой выгоды — лишняя сложность разработки.

Краткая шпаргалка

ЦельДействие
Включить AOT<PublishAot>true</PublishAot>
Self-containeddotnet publish -r linux-x64 --self-contained
Меньше globalization<InvariantGlobalization>true</InvariantGlobalization>
JSON без рефлексииJsonSerializerContext (source generator)

См. также