转自https://www.cnblogs.com/cnxkey/articles/6808311.html
luajit本身是没有问题的,但是在cocos项目中可能由于初始化内存无法分配导致有问题了,直接的证据就是jit.off()状态下比jit.on()状态下明显效率更高。
这里有篇文字对此进行了说明
http://www.cnblogs.com/zwywilliam/p/5999980.html18
3.1可供代码执行的内存空间被耗尽->要么放弃jit,要么修改luajit的代码
要jit,就要编译出机器码,放到特定的内存空间。但是arm有一个限制,就是跳转指令只能跳转前后32MB的空间,这导致了一个巨大的问题:luajit生成的代码要保证在一个连续的64MB空间内,如果这个空间被其他东西占用了,luajit就会分配不出用于jit的内存,而目前luajit会疯狂重复尝试编译,最后导致性能处于瘫痪的状态。
虽然网上有一些不修改luajit的方案(http://www.freelists.org/post/luajit/Performance-degraded-significantly-when-enabling-JIT,9),在lua中调用luajit的jit.opt的api尝试将内存空间分配给luajit,但根据我们的测试,在unity上这样做仍然无法保证所有机器上能够不出问题,因为这些方案的原理要抢在这些内存空间被用于其他用途前全部先分配给luajit,但是ulua可以运行的时候已经是程序初始化非常后期的阶段,这个时候众多的unity初始化流程可能早已耗光了这块内存空间。相反cocos2dx这个问题并不多见,因为luajit运行早,有很大的机会提前抢占内存空间。
无论从代码看还是根据我们的测试以及luajit
maillist的反馈来看,这个问题早在2.0.x就存在,更换2.1.0依然无法解决,我们建议,如果项目想要使用jit模式,需要在android工程的Activity入口中就加载luajit,做好内存分配,然后将这个luasate传递给unity使用。如果不愿意趟这个麻烦,那可以根据项目实际测试的情况,考虑禁用jit模式。一般来说,lua代码越少,遇到这个问题的可能性越低。
3.2寄存器分配失败->减少local变量、避免过深的调用层次
很不幸的一点是,arm中可用的寄存器比x86少。luajit为了速度,会尽可能用寄存器存储local变量,但是如果local变量太多,寄存器不够用,目前jit的做法是:放弃治疗(有兴趣可以看看源码中asm_head_side函数的注释)。因此,我们能做的,只有按照官方优化指引说的,避免过多的local变量,或者通过do end来限制local变量的生命周期。
3.3调用c函数的代码无法jit->使用ffi,或者使用2.1.0beta2
这里要提醒一点,调用c#,本质也是调用c,所以只要调用c#导出,都是一样的。而这些代码是无法jit化的,但是luajit有一个利器,叫ffi,使用了ffi导出的c函数在调用的时候是可以jit化的。
另外,2.1.0beta2开始正式引入了trace stitch,可以将调用c的lua代码独立起来,将其他可以jit的代码jit掉,不过根据作者的说法,这个优化效果依然有限。
3.4jit遇到不支持的字节码->少用for in pairs,少用字符串连接
有非常多bytecode或者内部库调用是无法jit化的,最典型就是for in pairs,以及字符串连接符(2.1.0开始支持jit)。
具体可以看http://wiki.luajit.org/NYI,只要不是标记yes或者2.1的代码,就不要过多使用。
4.怎么知道自己的代码有没有jit失败?使用v.lua
完整的luajit的exe版本都会带一个jit目录,下面有大量luajit的工具,其中有一个v.lua,这是luajit verbose
mode(另外还有一个很重要的叫p.lua,luajit
profiler,后面会提到),可以追踪luajit运行过程中的一些细节,其中就可以帮你追踪jit失败的情况。
local verbo = require("jit.v")
verbo.start()
当你看到以下错误的时候,说明你遇到了jit失败
failed to allocate mcode memory,对应错误3.1
NYI: register coalescing too complex,对应错误3.2
NYI: C function,对应错误3.3(这个错误在2.1.0beta2中已经移除,因为有trace stitch)
NYI: bytecode,对应错误3.4
这在luajit.exe下使用会很正常,但要在unity下用上需要修改v.lua的代码,把所有out:write输出导向到Debug.Log里头。