
开场很多 Unity 开发者在性能调优时都会遇到一个疑问:调用Transform.Translate这种高频 API 时,是不是每次都要穿越 C# 与 C++ 的边界?答案是肯定的,而且开销远比你想象的小。当你在 C# 脚本里写下transform.Translate(1, 0, 0),这个方法并没有托管实现——它会直接跳转到引擎底层的 C++ 函数。这个跨语言跳转对开发者几乎透明,背后靠的是一套启动期建立的注册与查找机制:ICall(Internal Call)。理解这套机制有三个实际收益:一是能正确评估"托管/原生边界"的真实开销,不再凭直觉误判性能热点;二是能读懂 Unity 托管层源码(UnityCsReference)里大量没有方法体的extern声明;三是写自定义原生插件时,知道哪条路是官方支持的、哪条是内部通道。一、核心概念:一张启动期建好的映射表ICall 是 Mono/IL2CPP 运行时提供的"托管调原生"通道。它的本质是一张哈希映射表:键是 C# 方法的完整签名(含命名空间),值是 C++ 函数指针。这张表在引擎启动早期一次性建好,之后每次跨语言调用就是一次 O(1) 查表加一次直接的函数调用。1.1 托管侧:只有声明,没有方法体C# 侧被原生实现的方法有两个标志:extern关键字,以及[MethodImpl(MethodImplOptions.InternalCall)]特性。开发者只写声明——因为实现根本不在托管