.NET 8 极致性能优化 AOT

前言

.NET8对于性能的优化是方方面面的,所以AOT预编译机器码也是不例外的。本篇来看下对于AOT的优化。

概述

首先要明确一个概念,.NET里面的AOT它是原生的。什么意思呢?也就是说通过ILC编译器(AOT编译器,参考:.Net 7 新编译器 ILC 简析)编译出来的代码是各个平台上可以直接运行的二进制代码。比如MacOS的二进制,Linux二进制等等。所以称之为原生。

C#源码被ILC编译之后,生成了一个完全原生态代码的可执行文件。在执行的时候不需要JIT来编译任何东西,因为JIT已经在ILC里面被充分利用过了。实际上AOT里面也没有包含JIT。那么它如何优化呢?只能是在ILC里面调用JIT的时候了。所以它这个优化依然依靠JIT。.NET8里面优化AOT的一个典型的例子,就是ASP.NET应用程序在使用AOT的时候表现不错,同时也降低了总成本。

在.NET8里面优化AOT的一个重要的目标就是减少AOT可执行文件的大小,关于这点的效果。我们现在就可以看到

下面创建一个控制台应用程序

dotnet new console -o nativeaotexample -f net7.0

由于上面是通过.NET7.0创建的,我们把这个控制台的csproj更改下

<TargetFramework>net7.0</TargetFramework>改为<TargetFrameworks>net7.0;net8.0</TargetFrameworks>

可以轻松的构建.NET7.0或者.NET8.0的程序

继续​​​​​​​

<PropertyGroup>...</PropertyGroup>项中添加如下<PublishAot>true</PublishAot>编译成AOT文件

下面我们就可以通过dotnet publish发布它了,linux如下:

dotnet publish -f net7.0 -r linux-x64 -c Release

现在它生成了一个.NET7.0版本的独立可执行文件,可通过 ls/dir 输出目录以查看生成的二进制大小

12820K /home/stoub/nativeaotexample/bin/Release/net7.0/linux-x64/publish/nativeaotexample

这个大约是13M左右,我们再来看下.NET8.0

dotnet publish -f net8.0 -r linux-x64 -c Release

生成的可执行文件大小如下:

1536K /home/stoub/nativeaotexample/bin/Release/net8.0/linux-x64/publish/nativeaotexample

1.5M的大小,这个优化的力度不可不大啊。整整优化了将近10的体积。这就是.NET8.0的优化魔力。

但是优化的情况远不止如此,比如说我们可以配置csproj使AOT的体积更小​​​​​​​

csproj添加如下size表示要生成的AOT大小<OptimizationPreference>Size</OptimizationPreference>

如果我们不需要全球化代码和数据,需要特的代码和数据,并且使用不变模式,可以csproj添加如下选项

<InvariantGlobalization>true</InvariantGlobalization>

如果你不想在AOT异常的时候抛出堆栈,那么你也可以在csproj里面添加如下

<StackTraceSupport>false</StackTraceSupport>

重新通过dotnet publish net8.0发布了之后,它的体积还可以继续减小

1248K /home/stoub/nativeaotexample/bin/Release/net8.0/linux-x64/publish/nativeaotexample

再次缩小了0.3M大小。

然而,你以为到此优化就为止了吗?并没有,.NET8不仅对AOT编译器内部进行了改进,而且还对单个库也进行了性能优化和改进。比如HttpClient。

当然除了体积的优化之外,还有其它的优化,比如避免了在读取静态字段时的辅助调用,再比如BenchmarkDotNet 也是支持AOT化的,也就是性能测试上面的支持。我们可以只使用 --runtimes nativeaot7.0 nativeaot8.0,而不使用 --runtimes net7.0 net8.0,如下代码​​​​​​​

// dotnet run -c Release -f net7.0 --filter "*" --runtimes nativeaot7.0 nativeaot8.0
using BenchmarkDotNet.Attributes;using BenchmarkDotNet.Running;
BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args);
[HideColumns("Error", "StdDev", "Median", "RatioSD")]public class Tests{    private static readonly int s_configValue = 42;
    [Benchmark]    public int GetConfigValue() => s_configValue;}

上面代码可以通过如下AOT化运行

dotnet run -c Release -f net7.0 --filter "*" --runtimes nativeaot7.0 nativeaot8.0

BenchmarkDotNet 输出如下

Method Runtime Mean Ratio
GetConfigValue NativeAOT 7.0 1.1759 ns 1.000
GetConfigValue NativeAOT 8.0 0.0000 ns 0.000

可以看到即使是性能测试的Benchmark,AOT优化也是不放过的。

另外还值得一提的地方就是分层,因为AOT里面没有分层的概念。但是即时编译也就是不是AOT编译的时候,一个方法从tier0提升到tier1,方法里面的静态字段必须被初始化过了。AOT里面添加了一个快速路径检查字段是否初始化,避免一些不必要的开销。

其它的一些改进,比如AOT锁的实现方式。使用了一种混合方式,开始使用轻量级自旋锁,后面升级到使用 System.Threading.Lock 类型,这个应该会在.NET9.0里面释放出来。

 

欢迎关注公众号(jianghupt),文章首发地。

优秀的个人博客,低调大师

微信关注我们

原文链接:https://my.oschina.net/u/5407571/blog/10316035

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
Mario,低调大师唯一一个Java游戏作品

Mario,低调大师唯一一个Java游戏作品

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Apache Tomcat7、8、9(Java Web服务器)

Apache Tomcat7、8、9(Java Web服务器)

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。

Eclipse(集成开发环境)

Eclipse(集成开发环境)

Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。

Java Development Kit(Java开发工具)

Java Development Kit(Java开发工具)

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。