Xamarin 预编译Xamarin.Mac ahead of time compilation

概述Overview

预先(AOT)编译是一种功能强大的优化技术,可提高启动性能。Ahead of time (AOT) compilation is a powerful optimization technique for improving startup performance. 但是,它还会以深远的方式影响生成时间、应用程序大小和程序执行。However, it also affects your build time, application size, and program execution in profound ways. 为了理解它所施加的折衷,我们将对应用程序的编译和执行进行一些探讨。To understand the tradeoffs it imposes, we’re going to dive a bit into the compilation and execution of an application.

用托管语言(例如C#和F#)编写的代码编译为名为 IL 的中间表示形式。Code written in managed languages, such as C# and F#, is compiled to an intermediate representation called IL. 存储在库和程序程序集中的这一 IL 相对紧凑,并可在处理器体系结构之间移植。This IL, stored in your library and program assemblies, is relatively compact and portable between processor architectures. 不过,IL 只是一组中间的指令,在某一时刻需要将 IL 转换为特定于处理器的计算机代码。IL, however, is only an intermediate set of instructions and at some point that IL will need to be translated into machine code specific to the processor.

可以执行以下两个操作:There are two points in which this processing can be done:

  • 实时 (JIT) –在应用程序的启动和执行期间,IL 将在内存中编译为计算机代码。Just in time (JIT) – During startup and execution of your application the IL is compiled in memory to machine code.
  • 提前(AOT) –在生成过程中,将编译 IL 并将其写出到本机库,并将其存储在应用程序捆绑包中。Ahead of time (AOT) – During build the IL is compiled and written out to native libraries and stored within your application bundle.

每个选项都有多个优点和折衷:Each option has a number of benefits and tradeoffs:

  • JITJIT
    • 启动时间–必须在启动时执行 JIT 编译。Startup Time – JIT compilation must be done on startup. 对于大多数应用程序,这是100ms 的顺序,但对于大型应用程序,这种情况可能会大大增加。For most applications this is on the order of 100ms, but for large applications this time can be significantly more.
    • 执行–由于可以针对所使用的特定处理器优化 JIT 代码,因此可以生成更好的代码。Execution – As the JIT code can be optimized for the specific processor being used, slightly better code can be generated. 在大多数应用程序中,这是最快的几个百分比点。In most applications this is a few percentage points faster at most.
  • AOTAOT
    • 启动时间–加载预编译的 DYLIB 比 JIT 程序集快得多。Startup Time – Loading pre-compiled dylibs is significantly faster than JIT assemblies.
    • 磁盘空间–这些 dylib 可能会占用大量的磁盘空间。Disk Space – Those dylibs can take a significant amount of disk space however. 根据 AOTed 的程序集,它可以使应用程序的代码部分翻倍或更大。Depending on which assemblies are AOTed, it can double or more the size of the code portion of your application.
    • 生成时间–对于 JIT 编译,它的运行速度明显降低,并将使用它来降低生成速度。Build Time – AOT compilation is significantly slower that JIT and will slow builds using it. 这种减速范围可以是几分钟到一分钟或更长时间,具体取决于编译的程序集的大小和数目。This slowdown can range from seconds up to a minute or more, depending on the size and number of assemblies compiled.
    • 模糊处理–作为 IL 比机器代码更容易进行反向工程,这并不是必需的,可将其去除以帮助对敏感代码进行模糊处理。Obfuscation – As the IL, which is significantly easier to reverse engineer than machine code, is not necessarily required it can be stripped to help obfuscate sensitive code. 这需要如下所述的 "混合" 选项。This requires the "Hybrid” option describe below.

启用 AOTEnabling AOT

在将来的更新中,会将 AOT 选项添加到 "Mac 生成" 窗格。AOT options will be added to the Mac Build pane in a future update. 在此之前,启用 AOT 要求通过 Mac Build 中的 "其他 mmp 参数" 字段传递一个命令行参数。Until then, enabling AOT requires passing a command line argument via the “Additional mmp arguments” field in Mac Build. 提供了以下选项:The options are as follows:

--aot[=VALUE]          Specify assemblies that should be AOT compiled
                          - none - No AOT (default)
                          - all - Every assembly in MonoBundle
                          - core - Xamarin.Mac, System, mscorlib
                          - sdk - Xamarin.Mac.dll and BCL assemblies
                          - |hybrid after option enables hybrid AOT which
                          allows IL stripping but is slower (only valid
                          for 'all')
                          - Individual files can be included for AOT via +
                          FileName.dll and excluded via -FileName.dll

                          Examples:
                            --aot:all,-MyAssembly.dll
                            --aot:core,+MyOtherAssembly.dll,-mscorlib.dll

混合 AOTHybrid AOT

在 macOS 应用程序的执行过程中,运行时默认为使用从 AOT 编译生成的本机库中加载的计算机代码。During execution of a macOS application the runtime defaults to using machine code loaded from the native libraries produced by AOT compilation. 但有些代码区域(如 trampolines),JIT 编译可以产生更多的优化结果。There are, however, some areas of code such as trampolines, where JIT compilation can produce significantly more optimized results. 这要求托管程序集 IL 可用。This requires the managed assemblies IL to be available. 在 iOS 上,应用程序被限制为使用 JIT 编译;这部分代码也是 AOT。On iOS, applications are restricted from any use of JIT compilation; those section of code are AOT compiled as well.

混合选项指示编译器编译这些节(如 iOS),同时还假定在运行时不会提供 IL。The hybrid option instructs the compiler to both compile these section (like iOS) but also to assume that the IL will not be available at runtime. 然后,可以将此 IL 去除生成后。This IL can then be stripped post build. 如上所述,在某些位置,运行时将强制使用不太优化的例程。As noted above, the runtime will be forced to use less optimized routines in some places.

更多注意事项Further considerations

通过处理的程序集的大小和数量来扩展 AOT 的不利影响。The negative consequences of AOT scale with the sizes and number of assemblies processed. 示例的完整目标框架包含比新式更大的基类库(BCL),因此 AOT 会花费很长时间,并生成更大的绑定。The Full target framework for example contains a significantly larger Base Class Library (BCL) than Modern, and thus AOT will take significantly longer and produce larger bundles. 与链接(去除未使用的代码)的整个目标框架不兼容时,这会更加复杂。This is compounded by the Full target framework’s incompatibility with Linking, which strips out unused code. 请考虑将应用程序移至新式,并启用链接以获得最佳结果。Consider moving your application to Modern and enabling Linking for the best results.

AOT 的另一个优点是改进了与本机调试和分析工具链的交互。One additional benefit of AOT comes with improved interactions with native debugging and profiling toolchains. 由于大部分基本代码会提前编译,因此它将具有在本机崩溃报告、分析和调试中更易于阅读的函数名称和符号。Since a vast majority of the codebase will be compiled ahead of time, it will have function names and symbols that are easier to read inside native crash reports, profiling, and debugging. JIT 生成的函数没有这些名称,通常显示为难以解析的未命名十六进制偏移量。JIT generated functions do not have these names and often show up as unnamed hex offsets that are very difficult to resolve.