.NET 5 中的隱藏特性


前言

雙十一當天 .NET 5 正式發布帶來了很多的新特性和改進,個人覺得非常香,並且花了 10 分鍾時間就把自己的 4 個 .NET Core 3.1 的項目升級到了 .NET 5,堪稱無痛。

但是,.NET 5 中還有一些沒有正式公開的隱藏特性,那么現在就開始介紹吧。

Crossgen 2

Crossgen 2 とは

Crossgen 其實就是眾所周知的 ReadyToRun 特性。該功能將你的程序集進行一定程度的 AOT 編譯,然后在運行時跟蹤熱路徑對一些方法進行帶有更多優化的 JIT 編譯,即分層編譯,這使得程序集的加載速度大幅提高。

但是 .NET 5 其實帶了 Crossgen 的下一個版本:Crossgen 2。

Crossgen 2 的代碼幾乎是從 CoreRT 繼承而來,並在此基礎上做了很大改進。CoreRT 可以對 .NET 程序集進行完全的原生優化編譯,編譯出來的東西就是完全 native 的,和 Go 的體驗完全一致。

Crossgen 2 則使用了這套方法,將你的程序集在支持范圍之內進行 Native AOT 編譯,然后運行時直接加載啟動,並根據運行情況再使用 JIT 編譯器進行進一步的優化,是一種混合 AOT 策略。

為什么說在支持范圍之內呢?因為 Native AOT 必然對動態加載和 Emit 等特性不友好,但是 Crossgen 2 對於這些地方則直接跳過,並且由於是混合 AOT 方案,運行時依然存留有 JIT,因此這些功能完全不會受到影響。

使用

使用方法很簡單,在你發布程序的時候加命令行參數 /p:PublishReadyToRun=true /p:PublishReadyToRunUseCrossgen2=true 即可,例如:

dotnet publish -c Release -r win-x64 /p:PublishReadyToRun=true /p:PublishReadyToRunUseCrossgen2=true

注意

由於該功能尚未正式發布,並且存在一些已知的問題還沒有解決,因此如果要使用的話建議對發布出的程序做好測試。

另外,.NET 6 將會用 Crossgen 2 代替現有的 Crossgen 1,追求穩定的話可以等到明年再用。

棧上替換

棧上替換とは

棧上替換,即 On Stack Replacement。這個特性允許在運行時,即使一個方法有活躍的棧幀也能直接替換實現。

因此對於分層 JIT 功能來說,這個特性就允許 JIT 將未經優化的代碼直接切換成經過優化的代碼,即使被切換的方法存在活躍棧幀也沒問題。

使用

這是一個運行時特性,需要通過設置兩個環境變量來開啟:

bash:

export COMPlus_TC_QuickJitForLoops=1
export COMPlus_TC_OnStackReplacement=1

cmd:

set COMPlus_TC_QuickJitForLoops=1
set COMPlus_TC_OnStackReplacement=1

pwsh:

$env:COMPlus_TC_QuickJitForLoops = 1
$env:COMPlus_TC_OnStackReplacement = 1

注意

當前僅支持 x64,且目前處於實驗性階段。

更激進的發布裁剪

發布裁剪とは

發布裁剪可以在發布時將沒有用到的代碼裁剪掉,使得發布出去的程序體積大幅度減小。

但是 .NET 5 默認的裁剪行為是程序集粒度的,意味着會保留用到了的程序集,哪怕你只用了程序集中的一個方法,整個程序集也會被保留下來。

但是 .NET 5 提供了一種更為激進的裁剪方式,基於方法粒度進行裁剪。

開啟這個特性之后,如果一個程序集只被調用了一個方法,那裁剪后將只會保留這一個方法,而不是保留整個程序集。

使用

使用方法很簡單,只需要發布時附帶命令行參數 /p:PublishTrimmed=true /p:TrimMode=Link 即可,例如:

dotnet publish -c Release -r win-x64 /p:PublishTrimmed=true /p:TrimMode=Link

如果因為動態加載需要保留一些方法、類型或者程序集的話,可以按照如下文章內的方法進行配置:

https://devblogs.microsoft.com/dotnet/customizing-trimming-in-net-core-5/

注意

由於這種方法較為激進,請確保發布后進行充分的測試,以免出現因為動態加載導致運行時找不到方法的問題。

實驗性運行時

.NET 大量的新功能已經轉移到專門的實驗性運行時倉庫進行開發了,例如:

  • NativeAOT:基於 RyuJIT 的完全原生編譯
  • NativeAOT-LLVM:使用 LLVM 做代碼生成的完全原生編譯
  • ManagedQuic:完全 C# 實現的 QUIC 協議
  • Utf8String:UTF-8 字符串類型
  • JsonCodeGen:使用代碼生成器的 JSON
  • s390x:.NET 在 s390x 架構的移植
  • FreeBSD:.NET 在 FreeBSD 系統的移植
  • MIPS64:.NET 在 MIPS64 架構的移植
  • RegexSRM:基於微軟研究院成果 Symbolic Regex Matcher 的正則表達式實現
  • DllImportGenerator:用於自動生成 P/Invoke 接口的代碼生成器

歡迎前往實驗倉庫中對應分支進行試用和貢獻代碼:https://github.com/dotnet/runtimelab

另外,MIPS64 的移植工作由國內龍芯社區團隊完成,並將在 .NET 6 並入官方主線,相關信息在 https://github.com/gsvm/loongson-dotnet

總結

.NET 5 有很多的沒有公開宣布的特性,其中很多特性都非常棒,雖然沒有正式發布的現階段可能還存在一些問題,后期也可能會有較大的改動,但是感興趣的讀者不妨提前體驗一波。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM