How .NET Actually Works

How .NET Actually Works

Soklin
Soklin
StudentยทOctober 9, 2026ยท0 แž…แžผแž›แž…แžทแžแŸ’แž

Most .NET developers don't know what happens after F5.

And that's exactly why they can't debug the hard problems.

Here's what actually happens when you run a .NET application:

๐—ฆ๐˜๐—ฒ๐—ฝ ๐Ÿญ: ๐—–๐—ผ๐—บ๐—ฝ๐—ถ๐—น๐—ฎ๐˜๐—ถ๐—ผ๐—ป
Your C# code doesn't compile to machine code. It compiles to IL (Intermediate Language) via Roslyn. IL is platform independent, which is why the same .dll runs on Windows, Linux, and macOS. This is the part most people get right.

๐—ฆ๐˜๐—ฒ๐—ฝ ๐Ÿฎ: ๐—ง๐—ต๐—ฒ ๐—ฅ๐˜‚๐—ป๐˜๐—ถ๐—บ๐—ฒ (๐—–๐—ผ๐—ฟ๐—ฒ๐—–๐—Ÿ๐—ฅ)
CoreCLR loads your assembly and does three things: resolves all dependencies, loads types and metadata, and sets up the garbage collector. This is where most startup performance problems live, and most developers never look here.

๐—ฆ๐˜๐—ฒ๐—ฝ ๐Ÿฏ: ๐—๐—œ๐—ง ๐—–๐—ผ๐—บ๐—ฝ๐—ถ๐—น๐—ฎ๐˜๐—ถ๐—ผ๐—ป
The JIT compiler converts IL to native machine code, method by method, on first call. That's why the first request to your API is always slower. Tiered compilation helps: Tier 0 compiles fast, then Tier 1 re-compiles hot methods with full optimizations. Dynamic PGO takes it further by using actual runtime data to optimize.

The alternative is NativeAOT, which compiles everything upfront at build time. No JIT, no startup penalty, smaller binaries. Tradeoff: no dynamic code generation.

๐—ฆ๐˜๐—ฒ๐—ฝ ๐Ÿฐ: ๐—˜๐˜…๐—ฒ๐—ฐ๐˜‚๐˜๐—ถ๐—ผ๐—ป
Your native code runs on the CPU while the GC and Thread Pool work alongside it the entire time:

The GC manages memory in three generations. Gen0 collects short-lived objects (most die here). Gen1 is a buffer. Gen2 holds long-lived objects and is expensive to collect. If your app has Gen2 collection spikes, that's where your latency problems come from.

The Thread Pool manages all your async work. Every time you await something, the Thread Pool decides which thread picks it up next.

๐—ช๐—ต๐˜† ๐˜๐—ต๐—ถ๐˜€ ๐—บ๐—ฎ๐˜๐˜๐—ฒ๐—ฟ๐˜€
Understanding this pipeline is the difference between guessing why your app is slow and knowing exactly where to look. Startup slow? Check JIT and assembly loading. Random latency spikes? Check GC Gen2 collections. High memory? Check object lifetimes.

แž…แžผแž›แžšแžฝแž˜แž€แžถแžšแž–แžทแž—แžถแž€แŸ’แžŸแžถ
0 แž˜แžแžทแž™แŸ„แž”แž›แŸ‹แžšแž แžผแžแž˜แž€แžŠแž›แŸ‹แž–แŸแž›แž“แŸแŸ‡ - แž…แžผแž›แž…แžทแžแŸ’แž แž•แŸ’แžŠแž›แŸ‹แž˜แžแžท แž“แžทแž„แž…แŸ‚แž€แžšแŸ†แž›แŸ‚แž€แžšแž”แžŸแŸ‹แžขแŸ’แž“แž€แž“แŸ…แž›แžพ CambostackแŸ”
แž”แžพแž€แž€แŸ’แž“แžปแž„ Cambostack