前言
.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更改下
net7.0 改為net7.0;net8.0
可以輕松的構建.NET7.0或者.NET8.0的程序
繼續
把... 項中添加如下true 編譯成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大小Size
如果我們不需要全球化代碼和數據,需要特定的代碼和數據,并且使用不變模式,可以csproj添加如下選項
true
如果你不想在AOT異常的時候拋出堆棧,那么你也可以在csproj里面添加如下
false
重新通過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里面釋放出來。
審核編輯:湯梓紅
-
二進制
+關注
關注
2文章
796瀏覽量
41757 -
程序
+關注
關注
117文章
3795瀏覽量
81406 -
代碼
+關注
關注
30文章
4825瀏覽量
69043 -
應用程序
+關注
關注
38文章
3292瀏覽量
57911 -
編譯器
+關注
關注
1文章
1642瀏覽量
49283
原文標題:.NET8極致性能優化AOT
文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論