.NET的AOT和发布功能

新版.NET中的AOT(Ahead-of-Time)技术已愈发成熟,AOT是指在程序运行之前就把代码编译成目标平台的原生机器码,而不依赖运行时的JIT(Just-in-Time)编译器,这能带来更小的发布体积、更快的启动速度、更小的内存占用和更高的安全性。AOT编译后的程序自带核心运行时(相比自包含方式小的多)。但是AOT技术具有一定限制:不支持反射、动态IL代码、动态加载程序集等语言特性。当前.NET生态中有大量三方库的实现都基于以上语法特性,这就导致很多三方库不支持AOT编译。

AOT技术的使用场景受限,对于不支持AOT的项目(例如.NET下的WPF应用),在发布时可以选择自包含运行时,那么程序在没有安装运行时的环境中依然能够运行,这种方式也是非常便捷的,唯一不足在于程序发布体积过大(自带完整运行时,体积达到100MB)。

下面简要介绍下如何使用AOT和发布功能。

发布功能

以一个WPF应用为例,演示如何将其打包成自带运行时的独立应用。

设置发布参数:

  • 部署模式

    • 依赖框架:不带.NET运行时
    • 独立:包含.NET运行时
  • 生成单个文件:将.NET运行时相关的类库打包到EXE中(加载时通过内存映射的方式高效加载)。但是原生DLL不会打包到一起,因为原生DLL不支持动态加载,可以通过以下设置将原生DLL打包到一起(运行时解压加载)

    <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>

  • 启动ReadyToRun编译:相当于部分AOT,依然保留JIT编译器(用以支持反射等特性代码的执行)

AOT

以一个CLI应用为例,演示如何使用AOT编译。使用AOT的前提是:项目支持使用AOT,其中最值得注意的就是对三方库的选择使用!

对于AOT编译的项目,上一节介绍的三个重要参数已失去设置意义:部署模式、生成单个文件、启用ReadyToRun编译。因为AOT本身已支持。

AOT参数设置主要通过修改项目文件来实现,常见的设置包括以下几项:

1
2
3
4
5
6
7
8
<!-- 启用 Native AOT -->
<PublishAot>true</PublishAot>
<!-- 可选:减小体积 -->
<StripSymbols>true</StripSymbols>
<OptimizationPreference>Size</OptimizationPreference>
<DebugType>none</DebugType>
<IlcGenerateStackTraceData>false</IlcGenerateStackTraceData>
<InvariantGlobalization>true</InvariantGlobalization>
  • PublishAot:是启动AOT编译的基本选项,必须设置。
  • StripSymbols:默认是false,设为true可移除调试符号,减小体积。
  • OptimizationPreference:默认是Speed,性能优先;改成Size可以减少发布体积。
  • DebugType:默认为Portable,设为none且配合StripSymbols=true可减小体积。
  • IlcGenerateStackTraceData:默认为true,改成false可减少堆栈跟踪信息节省空间,但异常堆栈不完整。
  • InvariantGlobalization:全球化支持,默认是true,改成false表明支持完整全球化支持(体积增大20%~30%)。

本例子未采用减小体积的措施时,最终程序体积为2.67MB,采用相应措施后体积为2.12MB。

技术选型建议

  • 开发小工具时,尽量使用AOT技术
  • 开发桌面应用时,尽量使用独立部署模式,且使用最新版本的.NET SDK(独立部署的体积更小)
  • 开发Web API项目时,如果可以就是用AOT技术,不行就是用传统方式

支持AOT的库

  • System.CommandLine:微软官方制作CLI工具的库。
  • System.Text.Json:微软官方JSON序列化和反序列化库。
  • Dapper:轻量级ORM框架。
  • VS自带的Web API模板和gRPC模板。

(转载本站文章请注明作者和出处lihaohello.top,请勿用于任何商业用途)

评论