JIT Compilation
The Just-In-Time compiler translates Microsoft Intermediate Language (MSIL) into native machine code at runtime, enabling platform optimization while keeping code portable across CLR targets.How JIT Works
- MSIL is CPU-agnostic - JIT produces native code per platform
- First call overhead - Compilation occurs on first method invocation; subsequent calls use cached native code
- ReadyToRun (R2R) - Pre-compiles assemblies to reduce startup latency
- Tiered compilation - Promotes hot methods to higher optimization tiers
- Profile-guided optimization - Inlines and unrolls frequently executed paths
- NativeAOT - Skips JIT entirely, compiling ahead of time
Garbage Collection
The CLR GC automatically reclaims unreachable heap objects. Understanding generations prevents allocation pressure and GC pauses.Generational Model
The .NET GC uses a three-generation model:- Gen0 - Collects frequently and cheaply (~100x more than Gen2)
- Gen1 - Intermediate generation
- Gen2 - Collects long-lived objects infrequently
- Large Object Heap (LOH) - Stores objects ≥85KB, not compacted by default
Key Points
- LOH is not compacted by default — use
GCSettings.LargeObjectHeapCompactionMode - Server GC vs Workstation GC - Trade throughput for latency
- Finalization queues objects for an extra GC cycle — avoid finalizers
- Use
ArrayPool<T>andMemoryPool<T>to reduce Gen0 pressure GC.Collect()is rarely correct in production code
Monitor GC generation counts with EventCounters in production; spikes in Gen2 collections indicate long-lived allocation leaks.
Type Safety
The CLR enforces that operations are valid for their operands’ types, preventing buffer overruns, invalid casts, and memory corruption.Type System Features
- Value types - Stored on stack; reference types on heap (by default)
- Boxing - Wraps value types in reference type heap objects — avoid in hot paths
- Unsafe code - Bypasses type safety with explicit opt-in
- Nullable reference types - C# 8+ adds compile-time null analysis
- Generic constraints - Enforce type relationships at compile time
- Pattern matching - Concise, safe type discrimination
Exception Handling
CLR exceptions provide a unified mechanism for error signalling across language boundaries. Proper handling prevents silent failures and data corruption.Exception Best Practices
Do
- Catch specific exception types
- Include contextual info in custom exception messages
- Register unobserved task exception handlers in apps
Don't
- Swallow exceptions silently
- Use exceptions for normal control flow
- Re-throw with
throw ex(loses stack trace)
Key Concepts
- All CLR exceptions derive from
System.Exception ExceptionDispatchInfopreserves stack traces when re-throwing async exceptionsAggregateExceptionwraps multiple async task faults- Filter clauses (
when) allow catching only specific error conditions - Global handlers:
AppDomain.UnhandledException,TaskScheduler.UnobservedTaskException
Use exception filters (
when) to log exceptions without catching them — you get diagnostics without altering control flow.Thread Management
The CLR thread pool and synchronization primitives enable concurrent execution while protecting shared state.Threading Primitives
- ThreadPool - Manages a pool of worker threads
- ThreadLocal<T> - Provides per-thread storage
- Monitor - Used by
lockkeyword under the hood - SemaphoreSlim - Async-compatible semaphore
- Interlocked - Lock-free atomic operations
- CancellationToken - Cooperative cancellation of long tasks
Important Guidelines
Thread.Sleepblocks a thread; preferTask.Delayfor async waitsThreadPool.QueueUserWorkItemis low-level; preferTask.Run- SemaphoreSlim is async-compatible; Semaphore is not
- Monitor.Enter/Exit used by lock keyword under the hood
- Interlocked operations provide lock-free atomic updates
Security & Enforcement
The CLR enforces security permissions, assembly trust levels, and identity-based access control.Security Features
- Strong naming - Ensures assembly identity and prevents tampering
- Data Protection API (DPAPI) - Replaces manual encryption for config secrets
- SecureString - Holds sensitive data in encrypted memory
- Principal and Identity - Underpin role-based access
- Span<T> and Memory<T> - Reduce attack surface by avoiding intermediate copies
- NuGet package auditing - Catches known vulnerable dependencies
Use Data Protection API
For secrets at rest
Enable NuGet Auditing
In CI pipelines
Apply Least Privilege
To service accounts