尝试在Unity中将 Player Setting->Other->AOT Compilation Options 设置为 nrgctx-trampolines=8192,nimt-trampolines=8192,ntrampolines=4096
nrgctx-trampolines=8192,nimt-trampolines=8192,ntrampolines=4096
因为没有设置这个而导致奔溃闪退的原因是默认 Mono Runtime 在 AOT 编译的时候给的 trampoline 配置太小,不适合我们这种设计优良,大量使用 interface,设计绝对遵照 OO 思想的稍大一些的项目。
AOT 就是区别于 JIT(Just In Time) 的另一个编译机制,全称是 Ahead Of Time,就是预先编译好,而不是在代码执行到了某个方法再进行编译,这样的话会有一些好处。
使用 AOT 编译的有点有以下优点:
- 加快程序启动速度
- 更强的内存共享机制
- 潜在的性能提升
AOT 默认编译时给 Trampolines 的参数有点低:
nrgctx-trampolines 默认为 1024
nimt-trampolines 默认为 128
ntrampolines 默认为 1024
这对于小一些的项目可能是够用的,因为整体项目的结构不会太复杂,使用到的接口、泛型、递归相对也不会太多,但是对于一个稍大一些的项目来说,特别是采用了某些设计良好的第三方库的项目来说,这就可能不够用了。
大概解释一下相关的几个名词:
Trampoline 是一些手写的非常短小的用来在 mono 运行时中执行很多操作的组件代码。主要是通过 JIT 使用到的本地代码宏在运行时动态生成的。它们通常都有与之相对应的 C 方法,在某些较为复杂的场景中,当 trampoline 无法胜任时,mono 运行时就会将这些复杂的操作交回给这些对应的 C 方法来执行。这也可以看作是将 JIT 代码的执行权交回给 runtime 的一种方式。
JIT Trampolines 这些 Trampoline 主要是 JIT 在首次调用某个方法的时候编译方法用的。当 JIT 在编译一个方法调用指令时,它并不会立刻就编译这个被调用到的方法。实际上,它会先创建一个 JIT Trampoline,同时创建一个指向这个 trampoline 的调用指令。当这个 JIT Trampoline 在调用到的时候,它会再调用 mono_magic_trampoline() 方法来编译这个 trampoline 实际指向的目标方法,然后将编译后的方法的指针地址返回给这个指向它的 trampoline。这个过程呢稍微有点慢,所以呢,mono_magic_trampoline() 方法会优化调用 JIT 代码的过程,它会先尝试调用已经通过 JIT 编译过的方法而不是立即通过 trampoline 直接进行调用。这些都是通过在 tramp-.c 文件中的 mono_patch_callsiete() 方法来完成的。
AOT Trampolines AOT Trampolines 和 JIT Trampolines 非常相似,但是 AOT Trampolines 接受的编译参数不是一个 Mono 方法而是一个 image+token 对。如果传入的用于编译的 image+token 对所指向的方法已经经过 AOT 编译过了,那么再次编译这个 image+token 对时,就会直接返回这个已编译方法的指针地址而不需要再次加载这个方法的元数据进行再次编译了。