本文へスキップ
.NET 10 Native AOT で高速起動を実現する実践ガイドのアイキャッチ画像
Performance Tuning

.NET 10 Native AOT で高速起動を実現する実践ガイド

公開: 更新: 約6分で読めます

Native AOT は、.NET アプリを事前にネイティブコードへコンパイルして、起動の速さと省メモリを両立させるしくみです。JIT のウォームアップが要らないぶん立ち上がりが速く、ランタイムの同梱も不要になります。この記事では .NET 10 を前提に、どんなときに効くのか、どう有効化するのか、移行でつまずきやすいところまでを実践目線でまとめました。数字は環境で上下するので、方向性の目安として読んでください。Native AOT を含む .NET 10 全体の新機能は .NET 10 の新機能完全ガイド で俯瞰できます。

Native AOT とは何か

通常の .NET アプリは、実行時に IL を JIT コンパイルしながら動きます。起動直後はまだ最適化が進んでおらず、少しずつ速くなっていく「ウォームアップ」の時間が必要です。Native AOT はこの工程を発行時に済ませてしまい、OS がそのまま実行できるネイティブバイナリを作ります。実行時に JIT もランタイムのロードも走らないので、プロセスが立ち上がった瞬間からフルスピードで動きます。

もう一つの特徴が、ランタイム非依存の単一実行ファイルになることです。トリミングで使わないコードを削ぎ落とし、.NET ランタイムのインストールされていない環境にもファイルを置くだけで動かせます。

どんなときに効くのか

Native AOT は万能ではなく、効く場面がはっきりしています。次のようなワークロードは恩恵が大きいところです。

  • CLI ツールや短命なプロセス — 起動して処理してすぐ終わる用途は、ウォームアップの割合が大きいほど速さが効きます。
  • サーバーレス / コールドスタート — Azure Functions のように呼ばれるたびに立ち上がる構成では、初回応答の遅さが目に見えて改善します。
  • コンテナ・高密度ホスティング — イメージが小さくなり、1 台に多数のインスタンスを詰めても軽い。
  • マイクロサービス — スケールアウト時の立ち上がりが速く、オートスケールの追従が良くなります。

逆に、プラグインを動的に読み込む、実行時にコードを生成する、といった動きが中心のアプリは Native AOT と相性が悪いので、無理に寄せない判断も大事です。

有効化はプロジェクト設定ひとつ

導入自体は拍子抜けするほど簡単です。プロジェクトファイルに 1 行足して発行するだけで始められます。

<PropertyGroup>
  <PublishAot>true</PublishAot>
</PropertyGroup>

あとはランタイム識別子(RID)を指定して Release 発行します。Native AOT は環境ごとにネイティブコードを吐くため、動かす OS / アーキテクチャに合わせてビルドします。

dotnet publish -c Release -r linux-x64

できあがるのはランタイム同梱の単一ネイティブ実行ファイルです。.NET のインストールされていないサーバーやコンテナにそのまま置いて動かせます。

起動が速くなる理由

速さの正体は、実行時にやっていた仕事を発行時へ前倒ししたことにあります。JIT のウォームアップも、ランタイムアセンブリの読み込みも起動時には発生しません。ASP.NET Core 10 の Minimal API を AOT で発行すると、自己完結バイナリで 20MB 未満・初回応答 100ms 未満といった水準に届くケースが報告されています。

通常発行(JIT)と Native AOT のアプリ起動時間の比較
JIT のウォームアップが不要になるぶん、Native AOT は起動(コールドスタート)が大きく短縮される。

サイズもメモリも軽くなる

トリミングで未使用コードを削るため、配布物が小さくなります。コンテナイメージは 60〜80% ほど縮むという報告もあり、レジストリの転送やスケール時のプル時間にも効いてきます。メモリも、フレームワーク依存で動かした同じコードに比べて初回応答後で 30〜40% ほど下がる傾向です。

通常発行と Native AOT のメモリ使用量・配布サイズの比較
Native AOT は配布サイズもメモリ使用量も小さく、コンテナや高密度ホスティングと相性が良い。

リフレクションからソースジェネレーターへ

移行でいちばん引っかかるのがここです。Native AOT は「発行時にすべて決める」方式なので、実行時に型を探したりコードを生成したりするリフレクション主体のライブラリは、そのままだと動きません。解決策は、同じことを発行時に済ませるソースジェネレーターへ置き換えることです。書き換えの手間はありますが、リフレクション経由より速くなるおまけまで付いてきます。

JSON はソースジェネレーターに寄せるのが定番です。JsonSerializerContext を用意して、リフレクションではなく生成済みコードでシリアライズします。

[JsonSerializable(typeof(Order))]
[JsonSerializable(typeof(Order[]))]
internal partial class AppJsonContext : JsonSerializerContext { }

builder.Services.ConfigureHttpJsonOptions(o =>
    o.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default));

同じ発想の仕組みが標準でそろっています。P/Invoke は LibraryImport、正規表現は GeneratedRegex、ログは LoggerMessage のソースジェネレーターに置き換えると、AOT 互換かつ高速になります。ビルド時には AOT 互換性アナライザーが警告を出してくれるので、危ないところは事前に気づけます。

ASP.NET Core を AOT で動かす

.NET 10 は ASP.NET Core の AOT 対応が実用段階に入り、標準的な書き方をしていれば多くの Minimal API やコントローラーがそのままコンパイルできます。AOT 発行を前提にするなら、機能を絞って起動を軽くした CreateSlimBuilder を使います。

var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.ConfigureHttpJsonOptions(o =>
    o.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonContext.Default));

var app = builder.Build();
app.MapGet("/orders/{id}", (int id) => Results.Ok(new Order(id)));
app.Run();

ルーティングは RequestDelegate ソースジェネレーターが AOT 互換なコードを自動生成します。gRPC も AOT に対応しているので、軽量なサービスを固めて置く構成に向いています。

.NET 10 で進んだところ

2026 年時点の最新は .NET 10(LTS、2025 年 11 月リリース)です。Native AOT まわりは着実に実用性が上がっています。

  • トリミング警告が減った — .NET 10 SDK の新しい既定により、以前は [DynamicDependency] の手当てが必要だった警告の多くが自動で解消されるようになりました。
  • ASP.NET Core の AOT が成熟 — Minimal API とコントローラーの多くが、特別な書き換えなしにコンパイルできる水準に。
  • サイズと起動の底上げ — 自己完結バイナリのさらなる小型化と、初回応答の短縮が進みました。

気をつけておくところ

  • プラットフォーム固有ビルド — RID ごとにネイティブコードを作るため、Linux 用と Windows 用は別々に発行します。CI で対象 RID を並べておくと楽です。
  • 動的読み込みは不可 — 実行時のアセンブリ読み込みやコード生成に依存する設計は AOT に載りません。
  • デバッグは Release 前提 — Native AOT は Release ビルドが基本です。開発中は通常の Debug で回し、AOT は発行・検証の段で確認する使い分けにします。
  • ビルド時間は伸びる — 発行時にネイティブコンパイルする分、発行は通常より時間がかかります。

まとめ

Native AOT は、起動の速さ・省メモリ・小さな配布物がまとめて効く場面でこそ価値が出ます。導入の勘所をチェックリストにしておきます。

  • CLI・サーバーレス・コンテナ・マイクロサービスなど、起動やサイズが効くワークロードから試す
  • <PublishAot>true</PublishAot> と RID 指定で発行し、まず自分のアプリで計測する
  • JSON・P/Invoke・正規表現・ログはソースジェネレーターへ置き換える
  • ASP.NET Core は CreateSlimBuilder を使い、AOT 互換性アナライザーの警告を潰す
  • RID ごとのビルドと Release 前提のデバッグ運用を CI に組み込む

エンハンスド株式会社では、Native AOT を含む .NET アプリの高速化から、クラウド前提のアーキテクチャ設計までを支援しています。

この記事をシェア

コピーしました

関連記事