我们的游戏品类特殊,对游戏对局内的画面流畅性要求极高。不允许出现可以明显察觉的卡顿。当我们解决了所有对象创建,JIT编译等带来的卡顿之后。还有一个较为棘手的卡顿来源就是GC。我们想了各种办法尽可能的减少对局内的内存分配。包括对UI的特殊处理,对网络消息的特殊处理。最后终于能够做到在一个对局之内不会产生GC。
但是,我们知道,这件事并不是一劳永逸的。随着关卡的继续开发,总有一天还会出现GC,有些内存分配是没办法彻底消除的,比如UI上变化的文字。因此我决定去搞mono本身。
首先是编译mono,这方面教程很多,比如【1】。然后就是设法开关GC,事实上mono内部有这样的功能函数,GC_enable和GC_disable,我们要做的不过是将这些符号导出。mono\mini\ldscript文件中描述了mono lib的导出符号,在其中增加GC_enable和GC_disable,重新编译,得到改造过的libmono.so。替换unity目录下的libmono(需要区分armv7和x86)
在C#中实现一个功能类,然后就可以愉快的开关GC功能了。
class GarbageCollection
{
#elif UNITY_ANDROID
[DllImport("mono")]
protected static extern void GC_enable();
[DllImport("mono")]
protected static extern void GC_disable();
#else
protected static void GC_enable()
{
}
protected static void GC_disable()
{
}
#endif
}
那么IOS平台呢,本来想使用跟android平台类似的方法。后来发现由于IOS上使用IL2CPP,mono被改造后集成进了libiPhone.a,同时大量符号都被导出了包括GC_enable和GC_disable,也就是说在IOS上我们可以直接使用这两个接口,编译时不会遇到任何问题。
最后,我们的功能类就是这个样子
class GarbageCollection
{
static bool enabled = true;
public static bool Enable
{
get
{
return enabled;
}
set
{
if (value == enabled)
{
return;
}
if (value)
{
try
{
GC_enable();
}
catch (System.Exception ex)
{
Debug.Log("GC exception!");
Debug.Log(ex.ToString());
}
}
else
{
try
{
GC_disable();
}
catch (System.Exception ex)
{
Debug.Log("GC exception!");
Debug.Log(ex.ToString());
}
}
enabled = value;
}
}
#if UNITY_IPHONE
[DllImport ("__Internal")]
protected static extern void GC_enable();
[DllImport ("__Internal")]
protected static extern void GC_disable();
#elif UNITY_ANDROID
[DllImport("mono")]
protected static extern void GC_enable();
[DllImport("mono")]
protected static extern void GC_disable();
#else
protected static void GC_enable()
{
}
protected static void GC_disable()
{
}
#endif
}
做个简单的测试,在update里面不断的分配内存,很高兴的看到内存在飙涨。(这话怎么感觉怪怪的)
【1】http://www.cnblogs.com/July7th/p/4736502.html
|