Unity接入ILRuntime时需要注意的问题

研究了一段时间用ILRuntime做热更的方式,感觉整体还是不错的,但是官方技术文档不是很详细,把重点需要注意的问题说明了一下,但是出现bug的情况多种多样,在此,我把自己遇到的问题记录一下,如有描述错误的,还请阅读者指正。

(以下把Unity3D工程中脚本记为Unity,把热更脚本的C#工程记为Hotfix)

1、Unity调用Hotfix的方法,开销相对较大。这里抽象比喻一下,假如同时调用10万次方法,Unity中调用自身方法的开销为1,那么Hotfix调用Unity方法的开销大约为5,Unity调用Hotfix方法的开销大约为20,这只是我的比喻,并非误导各位。这里说明一下,同时调用一次方法与调用一万次方法的差距会不一样,例如调用一次方法,开销0.0001ms与0.01ms是可以忽略不计的。而且在Unity编辑器中测试结果与真机测试的结果会有偏差,官方已说明:如果要比较ILRuntime和Lua的性能,请在真机上测试。

2、Hotfix中调用Unity中的数据结构和API时,尽量不要调用泛型相关的,因为泛型会用到不同的数据类型。这个在官方文档有说明。

3、Unity中调用Hotfix中的static方法,无需实例参数。但是调用非static方法需要传递所在类的实例(实例即为new一个类对象)。官方文档也有说明。

4、Unity中多次或频繁调用的Hotfix的方法,尽量将方法缓存为IMethod,然后再用Appdomain调用,这样可以减少获取方法的开销。尽量不要在Unity脚本的Update方法中调用Hotfix的方法,这样会相对降低性能(注意只是相对,如果是轻量级的应用基本可以忽略)。

5、Unity中运行Hotfix中方法,是通过CLR重定向的机制操作的。这里有一个比较严重的坑,就是不要在Hotfix类中写方法的重载,例如一个类中存在Check(string name)和Check(string name, Type type),不管Check方法是在Unity中调用还是Hotfix中调用,可能会有意想不到的异常,这个bug我排查了半天才找到,我遇到的异常信息如下:

TypeLoadException: Failure has occurred while loading a type.
ILRuntime.Runtime.Intepreter.ILIntepreter.Execute (ILRuntime.CLR.Method.ILMethod method, ILRuntime.Runtime.Stack.StackObject* esp, System.Boolean& unhandledException) (at Assets/ThirdParty/ILRuntime/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:2092)
Rethrow as ILRuntimeException: Failure has occurred while loading a type.
IL_0001: ldtoken T

6、Hotfix中继承Unity的类或接口,需要写Adaptor适配器;Hotfix调用Unity中带参数的委托,需要注册委托参数RegisterMethodDelegate;Hotfix中调用Unity中非Action和Func的委托,需要注册委托转换器,例如使用UnityAction。这些都在ILRuntime的官方Demo中有说明。

7、关于CLR重定向和CLR绑定,可以无需深入去了解,因为ILRuntime已经提供了直接生成CLR重定向代码的工具。这里说明一下CLR绑定,我们可以直接调用这行代码:ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain);,这其实就是利用了CLR重定向的原理。Hotfix中是可以直接调用Unity的方法,类似引用Unity的的脚本程序集一样,如果不提前进行CLR绑定,那么开销增加十倍甚至更高,所以CLR绑定就是提高性能的。官方Demo也说明了,CLR绑定会生成较多C#代码,最终会增大包体和Native Code的内存耗用,尤其在比较大的项目工程中更为突出,所以只添加常用类型和频繁调用的接口即可。例如Unity中一个Test类,整个生命周期中只在Hotfix中调用了一次,那么完全可以不用进行CLR绑定。但是一定要记得将CLR绑定的注册写在CLR重定向的注册后面,因为同一个方法只能被重定向一次,只有先注册的那个才能生效。

8、洗洗睡觉,未完待续……

你可能感兴趣的:(Unity3D)