What's New in the .NET 9 Runtime

Manager — SDE
Search for a command to run...

Manager — SDE
No comments yet. Be the first to comment.
← Previous: What’s New in the .NET 9 Runtime C# 13 introduces a collection of language enhancements that streamline code patterns, enable more powerful generics, improve low-level control, and provide smoother integrations with newer runtime featur...
← Previous: What’s New in the SDK and Tooling for .NET 9 .NET Aspire is a set of tools, templates, and packages designed to help developers build observable, production-ready apps that embrace cloud-native and distributed computing best practices. .N...

← Previous: What’s New in .NET Libraries for .NET 9 The .NET 9 SDK introduces several new capabilities and improvements to streamline development workflows, enhance build and test experiences, improve NuGet security and performance, and provide great...

← Previous: What’s New in .NET MAUI for .NET 9 .NET 9 adds a wide range of enhancements and new APIs across the base class libraries. These improvements touch everything from low-level data structures and cryptography to JSON serialization, text pr...

← Previous: What’s New in ML.NET .NET Multi-platform App UI (.NET MAUI) in .NET 9 focuses on improving overall product quality, test coverage, performance, and stability. While previous releases introduced major new capabilities and controls, the emp...

← Previous: What’s new in ASP.NET Core 9.0 ML.NET continues to evolve as a full-featured, open-source machine learning framework for .NET developers, enabling you to create, train, and deploy custom ML models directly in your .NET applications. ML....

← Previous: What's New in .NET 9
The .NET 9 runtime introduces a range of features and optimizations aimed at improving performance, reducing application size, enhancing security, and providing more flexible deployment options. These enhancements target both core runtime components and the JIT compiler, delivering faster execution times, smaller footprints, and safer execution environments.
In .NET 9, two new attributes—FeatureSwitchDefinitionAttribute and FeatureGuardAttribute—help developers define feature switches that integrate with trimming and Native AOT. By using these attributes, you can toggle areas of functionality at build time, removing unused code paths and reducing application size.
FeatureSwitchDefinitionAttribute:
This attribute treats a feature-switch property as a compile-time constant during trimming. When a feature is disabled in the app’s configuration, related code paths are removed from the final binary. Consider the following code:
if (Feature.IsSupported)
Feature.Implementation();
public class Feature
{
[FeatureSwitchDefinition("Feature.IsSupported")]
internal static bool IsSupported => AppContext.TryGetSwitch("Feature.IsSupported", out bool isEnabled) ? isEnabled : true;
internal static void Implementation() { /* ... */ }
}
By setting <RuntimeHostConfigurationOption Include="Feature.IsSupported" Value="false" Trim="true" /> in the project file, Feature.IsSupported is effectively treated as false, and the call to Feature.Implementation() is removed after trimming.
FeatureGuardAttribute:
This attribute identifies a feature-switch property as a guard for code annotated with RequiresUnreferencedCodeAttribute, RequiresAssemblyFilesAttribute, or RequiresDynamicCodeAttribute. For example:
if (Feature.IsSupported)
Feature.Implementation();
public class Feature
{
[FeatureGuard(typeof(RequiresDynamicCodeAttribute))]
internal static bool IsSupported => RuntimeFeature.IsDynamicCodeSupported;
[RequiresDynamicCode("Feature requires dynamic code support.")]
internal static void Implementation() { /* Uses dynamic code */ }
}
When publishing with <PublishAot>true</PublishAot>, this setup avoids certain analyzer warnings and removes unreachable code paths.
UnsafeAccessorAttribute—introduced in .NET 8—allows direct, unsafe access to private type members. In .NET 9, it now supports generic parameters for both CoreCLR and Native AOT scenarios. This expansion enables reflection-free access to generic fields and methods, improving advanced scenarios like performance-sensitive libraries and frameworks.
using System.Runtime.CompilerServices;
public class Class<T>
{
private T? _field;
private void M<U>(T t, U u) { }
}
class Accessors<V>
{
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_field")]
public extern static ref V GetSetPrivateField(Class<V> c);
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")]
public extern static void CallM<W>(Class<V> c, V v, W w);
}
With this feature, code that previously relied on reflection to manipulate generics can now use UnsafeAccessorAttribute for more efficient and predictable access.
Dynamic adaptation to application sizes (DATAS), introduced as an opt-in in .NET 8, is now enabled by default. DATAS adjusts memory usage dynamically based on the application’s long-lived data size. This approach helps the GC maintain a heap size proportional to actual memory requirements, improving overall performance and efficiency in real-world workloads.
For more details, see Dynamic adaptation to application sizes (DATAS).
CET is now enabled by default on Windows, providing hardware-enforced protection against return-oriented programming (ROP) exploits. CET improves application security by enforcing safer control-flow transitions. Although it may introduce a small performance overhead, CET can be disabled if necessary. This marks a significant step in hardening .NET applications against low-level attacks.
.NET 9 adds configuration options for how apps locate and load the .NET runtime. Developers can now more tightly control the search behavior, which is useful for private runtime installations or ensuring a stable, known environment.
The .NET 9 runtime delivers a wide array of performance optimizations. These improvements span JIT compilation, code generation, loop transformations, exception handling, and more. They include:
Loop Optimizations:
Enhanced induction-variable widening, post-indexed addressing on Arm64, strength reduction, and loop counter direction optimizations reduce instruction counts and increase throughput. Common looping patterns—such as iterating over arrays—are now executed more efficiently without any source code changes.
Inlining Improvements:
Shared generics that require runtime lookups can now be inlined, reducing overhead and enabling further optimizations. Accesses to thread-local statics on multiple platforms are also more easily inlined, cutting down instruction counts and improving runtime performance.
PGO Enhancements:
Dynamic profile-guided optimization (PGO), enabled by default since .NET 8, now drives more decisions, including optimizing type checks and casts based on observed runtime behavior. This leads to faster code paths for the common cases your application actually encounters.
Arm64 and SIMD Codegen:
Arm64 benefits from vectorization in .NET libraries, multi-register load/store instructions, post-indexed addressing, and store-pair instructions. AVX10v1 support and Arm SVE experimental support introduce new hardware acceleration paths, allowing .NET to leverage cutting-edge CPU instruction sets for even greater speed-ups.
Faster Exceptions:
The exception handling model now mirrors the NativeAOT runtime’s approach, eliminating Windows SEH and Unix emulation. As a result, handling exceptions is up to 2-4 times faster in micro-benchmarks, significantly improving scenarios where exceptions are part of normal execution (for example, certain parsing or cancellation operations).
Code Layout and Reduced Address Exposure:
The JIT compiler now rearranges basic blocks more effectively, using profile data to reduce branching. It also tracks addressed-exposed locals more accurately, avoiding unnecessary constraints that limit optimization opportunities.
Object Stack Allocation for Boxes:
Situations where value types need to be boxed (for example, passing them as objects) can now be optimized by stack-allocating the box when it doesn’t escape the current method. In some cases, the compiler can even reason about the values and remove the boxes entirely, generating more efficient code and reducing allocations.
The .NET 9 runtime brings substantial changes under the hood to deliver faster, more secure, and more efficient applications. Developers benefit from:
In the next part, we’ll explore What’s new in C# 13, the language updates accompanying this release, and how they integrate with the runtime to provide a more productive and modern development experience.
Subscribe to the blog to stay updated on the latest .NET developments!
Follow on social media: