8KB的C#貪吃蛇遊戲熱點答疑和.NET7版本

2023-01-16 12:01:02

在之前的一篇文章《看我是如何用C#編寫一個小於8KB的貪吃蛇遊戲》中,介紹了在.NET Core 3.0的環境下如何將貪吃蛇遊戲降低到8KB。不過也有很多小夥伴提出了一些疑問和看法,主要是下面這幾個方面:

  • .NET Core 3.0可以做到這麼小,那麼.NET7表現會不會更好?
  • 不敢在生產中用這樣的方式,我看CoreRT這個倉庫我看已經歸檔了。
  • 這樣子弄太麻煩了,有沒有更簡單的辦法?

今天筆者就給大家一一解答這些問題。

.NET7下的貪吃蛇遊戲、

我們知道在.NET7中已經發布了NativeAOT正式的支援,經過.NET5、.NET6的迭代,NativeAOT已經基本成熟可用,那麼在.NET7中重新編譯這個遊戲,有沒有什麼進步呢?讓我們來看一看。

有外網條件的朋友可以看下方的這個GITHUB連結的程式碼,這個程式碼就是提交了升級.NET7 NativeAOT的實現:
https://github.com/MichalStrehovsky/SeeSharpSnake/pull/24

使用.NET7單檔案發布

為了達到我們的目的,對於這個專案的csproj檔案需要有一些小的改動。首先就是將對應的TargetFramework修改為net7.0版本。

此時就已經完成.NET Core 3.1到NET7.0的遷移了,我們執行下面的命令,可以獲得一個65MB大小的程式,這個和之前.NET Core 3.1沒有什麼區別。

dotnet publish -r win-x64 -c Release

開啟IL Linker

另外後面的.NET版本支援更好的程式集剪裁,也就是IL Linker工具,我們執行命令列時/p:PublishTrimmed=true選項就可以啟用。

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

此時我們可以發現,只有11MB大小了,比.NET Core 3.0時代的25MB降低了一半多。

使用NativeAOT功能

然後我們就要開始使用.NET7的NativeAOT功能,需要在專案檔案中加入<PublishAot>true</PublishAot>選項。我們加入了一個條件,在平時不開啟,只有輸入不同Mode的時候才開啟。

dotnet publish -r win-x64 -c Release /p:Mode=NativeAOT

此時可以獲得一個2.86MB大小的程式,比.NET Core 3.0時代的4.7MB要小了快一半。

使用Moderate模式

繼續修改csproj檔案,讓它支援Moderate模式,也就是使用<IlcGenerateCompleteTypeMetadata>false</IlcGenerateCompleteTypeMetadata>不生成完整的型別後設資料,另外也用<IlcOptimizationPreference>Size</IlcOptimizationPreference>讓編譯器為程式大小進行優化,而不是速度。由於後面的模式也需要支援這個,所以加入了很多條件編譯的選項。

dotnet publish -r win-x64 -c Release /p:Mode=NativeAOT-Moderate

結果和上面的一樣的2.86MB,也就是說現在NativeAOT應該預設就是Moderate模式。

進一步移除無關資料

接下來我們進一步移除無關的資料。

  • 使用<EventSourceSupport>false</EventSourceSupport>關閉對EventSource的支援
  • 使用<UseSystemResourceKeys>true</UseSystemResourceKeys>刪除 System.* 程式集的異常訊息。
  • 使用<InvariantGlobalization>true</InvariantGlobalization>刪除全球化特定的程式碼和資料。
dotnet publish -r win-x64 -c Release /p:Mode=NativeAOT-High

此時我們再次釋出,可以看到大小已經降低到了2.15MB,比.NET Core 3.0時的3.0MB降低了快30%。

繼續移除無關資料

  • 通過<IlcGenerateStackTraceData>false</IlcGenerateStackTraceData>移除堆疊跟蹤資料
  • 通過<IlcInvariantGlobalization>true</IlcInvariantGlobalization>移除其它語言的支援
  • 通過<IlcFoldIdenticalMethodBodies>true</IlcFoldIdenticalMethodBodies>將相同的方法體進行合併。

只為我們省下了幾百KB,此時大小來到了1.88MB

關閉反射

接下來我們可以繼續使用<IlcDisableReflection>true</IlcDisableReflection>來關閉反射,移除掉一些反射的後設資料。

dotnet publish -r win-x64 -c Release /p:Mode=NativeAOT-ReflectionFree

關閉反射後,大小來到了1.21MB,這應該是不用騷操作能達到的最小大小了。

和.NET Core 3.0的對比

下圖是.NET7和.NET Core 3.0在不同模式下大小的對比,可以看到經過.NET 5.0、.NET 6.0的發展,NativeAOT變得更加成熟了。

模式 .NET Core 3.0 .NET7.0 幅度
單檔案發布 65MB 65MB 0%
IL Linker剪裁 25MB 11MB -56%
NativeAOT 4.7MB 2.86MB -40%
NativeAOT-High 3.0MB 1.88MB -38%
關閉反射 1.21MB 1.21MB 0%

關於CoreRT

在部落格園的評論中,看到有一位朋友留言,說不敢在生產環境中使用,而且CoreRT已經歸檔。其實大可放心的使用,CoreRT關閉的原因也正如下面連結倉庫裡面說的一樣,是程式碼已經合併到runtimelab/nativeaot專案中。
https://github.com/dotnet/corert

而NativeAOT已經從實驗室中畢業,合併到dotnet/runtime中了,也就是.NET7看到的<PublishAot>選項,可以關注下面的微軟檔案。
https://learn.microsoft.com/zh-cn/dotnet/core/deploying/native-aot/

NoRuntime用起來很折騰

另外看到評論區大家吐槽的點就是後面那些騷操作看起來很麻煩,有沒有更簡單的方式?這個其實是有的,上篇文章的作者推出了bflat這個專案。

bflat是Roslyn(生成.NET可執行檔案的"官方"C#編譯器)和NativeAOT(née CoreRT)的混合物,NativeAOT(née CoreRT)是基於CoreCLR的.NET的提前編譯器。因此,您可以使用高效能 CoreCLR GC 和本機程式碼生成器 (RyuJIT) 存取最新的 C# 功能。

bflat 將兩個元件合併到一個用於 C# 的提前交叉編譯器和執行時中。bflat目前可以針對:

  • x64/arm64 基於 glibc 的 Linux(x64 (~CentOS 7) 上為 2.17 或更高版本,arm64 (~Ubuntu 18.04)上為 2.27 或更高版本)
  • arm64 基於 bionic 的 Linux(Android API 級別 21)
  • x64/arm64 Windows (Windows 7 或更高版本)
  • x64 UEFI(僅適用於--stdlib:zero)

對基於 musl 的 Linux 的支援正在開發中。bflat 可以生成本機可執行檔案,也可以生成可通過 FFI 從其他語言呼叫的本機共用庫,下面是它的開源地址:
https://github.com/bflattened/bflat

使用NoRuntime模式最小可以做到4KB大小,而且支援無作業系統裸機UEFI啟動。

總結

我們可以驚喜的看到NativeAOT經過幾年的發展已經逐步走向成熟,另外還有裸機可執行的C#程式,這給了我們很多的想象空間,可能有那麼一天C#程式會執行在只有幾百KB記憶體的物聯網終端裝置上,UEFI啟動程式使用C#編寫等等。

.NET效能優化交流群

相信大家在開發中經常會遇到一些效能問題,苦於沒有有效的工具去發現效能瓶頸,或者是發現瓶頸以後不知道該如何優化。之前一直有讀者朋友詢問有沒有技術交流群,但是由於各種原因一直都沒建立,現在很高興的在這裡宣佈,我建立了一個專門交流.NET效能優化經驗的群組,主題包括但不限於:

  • 如何找到.NET效能瓶頸,如使用APM、dotnet tools等工具
  • .NET框架底層原理的實現,如垃圾回收器、JIT等等
  • 如何編寫高效能的.NET程式碼,哪些地方存在效能陷阱

希望能有更多志同道合朋友加入,分享一些工作中遇到的.NET效能問題和寶貴的效能分析優化經驗。目前一群已滿,現在開放二群,可以直接掃碼進入。

如果提示已經達到200人,可以加我微信,我拉你進群: ls1075

另外也建立了QQ群,群號: 687779078,歡迎大家加入。