0Pricing
C# Academy · Lektion

ReadyToRun und tiered Compilation

Verstehen Sie ReadyToRun-Vorkompilierung, tiered JIT-Kompilierung und PGO (profilgeführte Optimierung) in .NET.

ReadyToRun und tiered Compilation ist eine kostenlose C# Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des C# Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

JIT, R2R und Tiered Compilation

.NET verwendet mehrere Kompilierungsstrategien, um Startgeschwindigkeit und maximalen Durchsatz auszubalancieren. Wenn Sie JIT, ReadyToRun und Tiered Compilation verstehen, können Sie die richtigen Einstellungen für Ihren Workload auswählen.

Funktionsweise des JIT

Der Just-in-Time- (JIT-)Compiler wandelt den IL-Bytecode beim ersten Aufruf jeder Methode in nativen Maschinencode um. Dadurch entsteht eine Verzögerung beim ersten Aufruf, gleichzeitig wird jedoch hochoptimierter Code für die aktuelle Maschine erzeugt.

// What happens at runtime:
// 1. App starts — methods are stubs pointing to the JIT
// 2. First call to MyMethod() → JIT compiles IL → native x64 code
// 3. Subsequent calls → native code runs directly (no JIT overhead)

// Startup cost: each method's first call takes microseconds for JIT
// Peak performance: excellent — JIT knows the actual CPU features

// .NET 9 JIT optimizations applied automatically:
// - Inlining
// - Loop unrolling
// - Escape analysis
// - SIMD vectorization
// - Profile-Guided Optimization (PGO)

ReadyToRun-(R2R)-Kompilierung

ReadyToRun (R2R) kompiliert Ihre Assemblys zur Veröffentlichungszeit vorab in nativen Code. Die Anwendung startet schneller, weil die JIT-Arbeit bereits erledigt ist – dafür ist die Größe auf dem Datenträger größer.

// Enable R2R in .csproj:
<PropertyGroup>
  <PublishReadyToRun>true</PublishReadyToRun>

  <!-- Optional: composite R2R — whole app in one native image -->
  <PublishReadyToRunComposite>true</PublishReadyToRunComposite>
</PropertyGroup>

// Publish:
dotnet publish -c Release -r linux-x64 --self-contained

// Benefits:
// - Startup time improvement: ~20-30% faster than JIT-only
// - No runtime required (self-contained)

// Trade-off:
// - Larger binary (IL + R2R code both stored)
// - Publish takes longer (cross-gen2 runs at publish time)

R2R im Vergleich zu Native AOT

R2R liefert weiterhin IL zusammen mit dem nativen Code aus und benötigt nach wie vor die .NET-Laufzeit. Native AOT entfernt IL und die Laufzeit vollständig. Treffen Sie Ihre Wahl abhängig von Ihren Bereitstellungsanforderungen.

// ReadyToRun:
// ✓ Still ships IL (fallback JIT for dynamically-generated code)
// ✓ Supports full reflection
// ✓ .NET runtime required on target
// ✓ Startup: ~30% faster than JIT
// Size: medium (IL + native)

// Native AOT:
// ✓ No IL, no runtime needed on target
// ✓ Startup: ~36x faster than JIT
// ✗ No reflection (must use source generators)
// ✗ Trimming limitations
// Size: smallest

// JIT only:
// ✓ Full reflection, no limitations
// ✓ Best peak throughput via PGO
// ✗ Slowest startup

Tiered Compilation

Tiered Compilation ist in .NET standardmäßig aktiviert. Methoden beginnen auf Tier 0 (schnelle Kompilierung), und häufig verwendete Methoden werden im Hintergrund auf Tier 1 (vollständige Optimierung) neu kompiliert.

// Tiered compilation lifecycle:
// Tier 0: fast JIT with minimal optimization
//   → method is callable in ~100 microseconds
// After ~30 calls (configurable): marked as "hot"
// Tier 1: full JIT with all optimizations + PGO
//   → background thread re-compiles the method
//   → future calls use optimized native code

// Usually transparent — you don't need to configure it
// Disable (rarely needed, only for debugging JIT issues):
// DOTNET_TieredCompilation=0

// Disable tiered PGO if benchmarking:
// DOTNET_TieredPGO=0

Profilgesteuerte Optimierung (PGO)

.NET 8+ enthält Dynamic PGO standardmäßig. Die Laufzeit sammelt auf Tier 0 Aufrufprofildaten und verwendet dieses Profil anschließend, um hochspezialisierten Tier-1-Code für häufig verwendete Pfade zu erzeugen.

// PGO automatically specializes code like:

// Before PGO (generic virtual dispatch):
void Process(IAnimal animal) => animal.Speak();
// → runtime checks type on every call

// After PGO (type-specialized inline):
void Process(IAnimal animal)
{
    if (animal is Dog)     { /* inlined Dog.Speak() */ }
    else if (animal is Cat){ /* inlined Cat.Speak() */ }
    else animal.Speak();   // slow path
}

// Enabled by default in .NET 8+
// Verify:
// DOTNET_ReadyToRun=0
// DOTNET_TieredCompilation=1  (default)
// DOTNET_TieredPGO=1          (default .NET 8+)

Startup-Hooks

Startup-Hooks (DOTNET_STARTUP_HOOKS) ermöglichen es Ihnen, Code auszuführen, bevor Main gestartet wird. Das ist für Diagnosen, Konfigurationsüberschreibungen oder Instrumentierung nützlich, ohne den Anwendungscode zu ändern.

// Create a hook class:
public class StartupHook
{
    public static void Initialize()
    {
        Console.WriteLine("[StartupHook] Initializing before Main");
        // e.g., register telemetry, inject config overrides
        Environment.SetEnvironmentVariable("FEATURE_FLAG", "1");
    }
}

// Compile to a DLL and set the env var:
export DOTNET_STARTUP_HOOKS=/path/to/MyHook.dll

// Then run your app normally:
dotnet run
// [StartupHook] Initializing before Main
// [Your App Output]

Laufzeitkonfigurationseinstellungen

Die .NET-Laufzeit stellt Umgebungsvariablen und Einstellungen in runtimeconfig.json bereit, mit denen Sie GC, Threadpool und JIT-Verhalten ohne Codeänderungen anpassen können.

// runtimeconfig.template.json (baked into app at publish):
{
  "configProperties": {
    "System.GC.Server": true,           // server GC (multi-core)
    "System.GC.Concurrent": true,       // background GC
    "System.GC.HeapHardLimit": 536870912, // 512 MB hard limit
    "System.Threading.ThreadPool.MinThreads": 20,
    "System.Threading.ThreadPool.MaxThreads": 200,
    "System.Runtime.TieredCompilation": true
  }
}

// Environment variable overrides (useful in containers):
// DOTNET_GCHeapHardLimit=536870912
// DOTNET_ThreadPool_UnfairSemaphoreSpinLimit=70
// DOTNET_GCConserve=1  // reduce memory at cost of throughput

Crossgen2 und Composite-Images

Crossgen2 ist das Tool, das R2R-Images erzeugt. Composite R2R kompiliert eine gesamte Anwendung (Anwendung und Framework) vorab in ein gemeinsames natives Image, um den bestmöglichen Start zu erreichen.

// Composite R2R: compile app + framework into one native image
<PropertyGroup>
  <PublishReadyToRun>true</PublishReadyToRun>
  <PublishReadyToRunComposite>true</PublishReadyToRunComposite>
</PropertyGroup>

// Normal R2R includes multiple images per assembly
// Composite merges them → fewer file reads at startup

// Manual crossgen2 invocation:
dotnet tool install -g dotnet-crossgen2
crossgen2 \
  --composite \
  --out composite.dll \
  MyApp.dll framework/System.Runtime.dll

// Inspect R2R content:
dotnet-ildasm --methodheader MyApp.dll | grep --color R2R

Praxisbeispiel: Start von ASP.NET Core optimieren

Eine Checkliste mit praktischen Einstellungen, um die Startleistung eines ASP.NET-Core-Dienstes in der Produktion zu maximieren.

// .csproj:
<PublishReadyToRun>true</PublishReadyToRun>  // pre-JIT at publish
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
<TieredCompilation>true</TieredCompilation>   // default

// Program.cs — avoid startup work:
// ✓ Use AddHealthChecks() NOT AddDbContextCheck() for faster probe
// ✓ Lazy-initialize expensive singletons
// ✓ Don't await long tasks in Program.cs before app.Run()

// Container settings:
// DOTNET_GCServer=1             → server GC for multi-core pods
// DOTNET_GCHeapHardLimit=536870912 → prevent OOM in constrained pods
// DOTNET_ThreadPool_MinThreads=20  → reduce thread starvation under burst load

// Measure startup:
// app.MapGet("/startup-time",
//   () => $"Ready in: {Stopwatch.GetElapsedTime(startTimestamp).TotalMs}ms");

Kurzer Check

Was ist der wesentliche Unterschied zwischen ReadyToRun (R2R) und Native AOT?

Zusammenfassung: ReadyToRun und Tiered Compilation

Wichtigste Erkenntnisse:

  • Tiered Compilation: Standard in .NET – Tier 0 (schnelle Kompilierung) → Tier 1 (optimiert + PGO)
  • Dynamic PGO: Standard ab .NET 8 – die Laufzeit profiliert häufig verwendete Pfade und spezialisiert den Tier-1-Code
  • ReadyToRun: vorkompiliert bei der Veröffentlichung; etwa 30 % schnellerer Start; benötigt weiterhin die Laufzeit; unterstützt Reflection
  • Native AOT: kein IL, keine Laufzeit; etwa 36-mal schnellerer Start; kein Reflection; kleinste Binärdatei
  • Passen Sie die Einstellungen über runtimeconfig.json und Umgebungsvariablen an (GC, Threadpool, JIT-Einstellungen)
  • Composite R2R führt Anwendung und Framework für den bestmöglichen Start in einem nativen Image zusammen

Häufig gestellte Fragen

Ist die Lektion „ReadyToRun und tiered Compilation“ kostenlos?

Ja — der vollständige Text von „ReadyToRun und tiered Compilation“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C# Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „ReadyToRun und tiered Compilation“?

Verstehen Sie ReadyToRun-Vorkompilierung, tiered JIT-Kompilierung und PGO (profilgeführte Optimierung) in .NET. Du übst C# Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um C# Academy zu starten?

Keine Vorkenntnisse erforderlich. C# Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „ReadyToRun und tiered Compilation“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser C# Academy-Lektion Code schreiben und ausführen?

Ja. Jede C# Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Native-AOT-Kompilierung
  2. Trimming und Einschränkungen durch Reflection
  3. ReadyToRun und tiered Compilation
  4. Benchmarking mit BenchmarkDotNet
← Zurück zu C# Academy