IL2CPP(Intermediate Language To C++)脚本后端是 Mono 后端的替代方案。IL2CPP 为更广泛平台上的应用程序提供更好的支持。IL2CPP 后端将 MSIL(Microsoft 中间语言)代码(例如,脚本中的 C# 代码)转换为 C++ 代码,然后使用 C++ 代码为所选平台创建原生二进制文件(例如,.exe、.apk 或 .xap)。
这种编译方式称为提前 (AOT) 编译,即 Unity 在构建本地二进制文件时,针对目标平台专门编译代码。Mono 后端在运行时使用一种称为即时编译 (JIT) 的技术来编译代码。
在此页面上:
某些平台不支持 AOT 编译,因此__ IL2CPP__ 后端并非适用于所有平台。其他平台支持 AOT 和 IL2CPP,但不允许 JIT 编译,因此无法支持 Mono 后端。当平台可以同时支持两个后端时,默认为 Mono。有关更多信息,请参阅脚本限制。
IL2CPP 可以提高各种平台的性能,但在构建的应用程序中包含机器代码的需求会增加构建时间和最终构建的应用程序的大小。有关更多信息,请参阅 IL2CPP 的工作原理和博客系列IL2CPP 内部简介。
IL2CPP 支持使用与 Mono 脚本后端相同的方式调试托管代码。想了解更多相关信息,请参阅在 Unity 中调试 C# 代码。
要使用 IL2CPP 构建项目,需要在 Unity 安装过程中安装后端。首次安装 Unity 版本时,可以选择 IL2CPP 作为可选模块,也可以通过 Unity Hub 将 IL2CPP 支持添加到现有安装中。有关更多信息,请参阅安装 Unity Hub 以及将模块添加到 Unity 编辑器。
IL2CPP 还需要目标平台原生的一些系统来生成 C++ 代码。这意味着要在特定平台上使用 IL2CPP,需要在该平台上构建应用程序。例如,要将 IL2CPP 与 MacOS 结合使用并作为构建目标,需要在使用 MacOS 的机器上构建应用程序。有关桌面平台的系统要求(包括各个平台的 IL2CPP 要求)的更多信息,请参阅 Unity 系统要求的 Desktop 部分。
您可以通过以下两种方法的其中一种来更改 Unity 用于构建应用程序的脚本后端:
通过编辑器中的播放器设置 (Player Settings) 菜单。执行以下步骤可通过播放器设置 (Player Settings) 菜单更改脚本后端:
还可以从构建配置文件 (Build Profiles) 窗口打开播放器设置 (Player Settings) 菜单;转到文件 (File) > 构建配置文件 (Build Profiles),然后单击播放器设置 (Player Settings) 选项卡。
通过编辑器脚本 API。使用 PlayerSettings.SetScriptingBackend 属性可更改 Unity 使用的脚本后端。
要开始构建过程,请打开构建配置文件 (Build Profiles) 窗口并单击构建 (Build) 按钮。Unity 随后将 C# 代码和程序集转换为 C++,最后为目标平台生成二进制文件。
使用 IL2CPP 开始构建时,Unity 会自动执行以下步骤:
IL2CPP 和 Mono 均提供了一些有用的选项;可通过脚本中的属性来控制这些选项。有关更多信息,请参阅依赖于平台的编译。
IL2CPP 使 Unity 能够为特定平台预编译代码。Unity 在此过程结束时生成的二进制文件已包含目标平台所需的机器代码,而 Mono 必须在运行时执行期间编译此机器代码。AOT 编译确实会增加构建时间,但也会提高与目标平台的兼容性并提高性能。
两个脚本后端都需要针对每个目标平台重新构建。例如,要同时支持 Android 和 iOS 平台,需要构建两次应用程序并生成两个二进制文件。
程序集剥离阶段有助于减小最终二进制文件的大小。Unity 会删除最终构建的应用程序不使用的任何字节码。
使用 IL2CPP 时的项目构建时间可能明显长于使用 Mono 时的项目构建时间。但是,可以执行几项操作来减少构建时间。
将项目排除在反恶意软件扫描之外
在构建项目之前,可以从反恶意软件扫描中排除 Unity 项目文件夹和目标构建文件夹。
将项目和目标构建文件夹存储在固态硬盘 (SSD) 上
与传统硬盘驱动器 (HDD) 相比,固态硬盘 (SSD) 具有更快的读/写速度。将 IL 代码转换为 C++ 并对其进行编译的过程涉及大量的读/写操作,因此更快的存储设备可加快此过程。
在播放器设置 (Player Settings)中更改 IL2CPP 代码生成 (IL2CPP Code Generation) 选项
要更改 IL2CPP 生成代码的方式,请打开播放器设置 (Player Settings)并配置 IL2CPP 代码生成 (IL2CPP Code Generation) 选项。默认情况下,会启用更快运行时 (Faster runtime) 选项,这样将生成更多机器代码,从而减少 IL2CPP 在运行时的影响。为了减少构建时间,可将此选项设置为 Faster(较小)构建。此方法在二进制可执行文件中生成和包含的机器代码更少,因此可能会降低运行时性能,但也会显著减少构建时间和二进制文件大小。
使用 IL2CPP 脚本后端时,可以控制 il2cpp.exe 生成 C++ 代码的方式。可以使用 Il2CppSetOption 属性启用或禁用以下运行时检查:
| 属性: | 描述: | 默认值: |
|---|---|---|
| Null checks | 如果启用此选项,则 IL2CPP 生成的 C++ 代码将包含 null 检查,并根据需要抛出托管的 NullReferenceException 异常。如果禁用此选项,则 IL2CPP 不会将 null 检查放入生成的 C++ 代码中。对于某些项目,禁用此选项可能会提高运行时性能。 禁用此设置后,Unity 不会阻止尝试访问生成的代码中的 null 值,这可能会导致出现不正确的行为。应用程序在取消引用 null 值后不久可能会崩溃。Unity 建议不要禁用此选项。 |
Enabled |
| Array bounds checks | 如果启用此选项,则 IL2CPP 生成的 C++ 代码将包含数组边界检查,并根据需要抛出托管的 IndexOutOfRangeException 异常。如果禁用此选项,则 IL2CPP 不会将数组边界检查放入生成的 C++ 代码中。 对于某些项目,禁用此选项可能会提高运行时性能。但是,当禁用此选项时,Unity 不会阻止在生成的代码中对具有无效索引的数组的任何访问,这并可能导致不正确的行为,包括读取或写入任意内存位置。在大多数情况下,这些内存访问在发生时不会表现出任何直接副作用,可能会悄无声息破坏应用程序状态。这可能会使调试这些错误变得极为困难。Unity 建议保持启用此选项。 |
Enabled |
| Divide by zero checks | 如果启用此选项,则 IL2CPP 生成的 C++ 代码将包含整数除法的除以零检查,并根据需要抛出托管的 DivideByZeroException 异常。如果禁用此选项,则 IL2CPP 不会将整数除法的除以零检查放入生成的 C++ 代码中。 这些检查会影响运行时的性能。仅当需要运行除以零检查时,才应启用此选项;否则,应禁用此选项。 |
Disabled |
要使用 Il2CppSetOption 属性:
以下示例描述了如何使用 Il2CppSetOption 属性:
[Il2CppSetOption(Option.NullChecks, false)]
public static string MethodWithNullChecksDisabled()
{
var tmp = new object();
return tmp.ToString();
}
可将 Il2CppSetOption 属性应用于程序集、类型、方法和属性。Unity 在最局部的作用域内使用该属性。
[Il2CppSetOption(Option.NullChecks, false)]
public class TypeWithNullChecksDisabled
{
public static string AnyMethod()
{
// Unity doesn’t perform null checks in this method.
var tmp = new object();
return tmp.ToString();
}
[Il2CppSetOption(Option.NullChecks, true)]
public static string MethodWithNullChecksEnabled()
{
// Unity performs null checks in this method.
var tmp = new object();
return tmp.ToString();
}
}
public class SomeType
{
[Il2CppSetOption(Option.NullChecks, false)]
public string PropertyWithNullChecksDisabled
{
get
{
// Unity doesn’t perform null checks here.
var tmp = new object();
return tmp.ToString();
}
set
{
// Unity doesn’t perform null checks here.
value.ToString();
}
}
public string PropertyWithNullChecksDisabledOnGetterOnly
{
[Il2CppSetOption(Option.NullChecks, false)]
get
{
// Unity doesn’t perform null checks here.
var tmp = new object();
return tmp.ToString();
}
set
{
// Unity performs null checks here.
value.ToString();
}
}
}