欢迎参与讨论,转载请注明出处。
前言
先前看到用好Lua+Unity,让性能飞起来—LuaJIT性能坑详解一文中提到:
3.2 寄存器分配失败->减少local变量、避免过深的调用层次
很不幸的一点是,arm中可用的寄存器比x86少。LuaJIT为了速度,会尽可能用寄存器存储local变量,但是如果local变量太多,寄存器不够用,目前JIT的做法是:放弃治疗(有兴趣可以看看源码中asm_head_side函数的注释)。因此,我们能做的,只有按照官方优化指引说的,避免过多的local变量,或者通过do end来限制local变量的生命周期。
对此自然是可以理解的,哪怕是一般语言,local变量过多也会有堆栈溢出的问题。不过我对此一直有个隐忧:Lua是拥有模块级local变量的,不知是否也受此规则影响?尽管有此隐忧,却一直没有去做相关的探究。恰逢今日遇到相关话题,便来个刨根问底吧。
200限制
首先的发现是:一段过程下最多拥有200个local变量,且do end
不算。类似这样:
|
|
如果超过199,则会报出main function has more than 200 local variables
的错误。当然这里说的是一段过程,所以函数是另算的,同样一个函数的过程最多也不能超过200个local变量(调用函数则算转入下一个过程了)。
这个限制是Lua与LuaJIT共有的,显然是想限制local数量的泛滥。
函数嵌套调用
接下来便是试试函数嵌套调用了:
|
|
注意参数v也算是local变量的一员,所以test变量最多只能延伸到199个。以此进行递归调用的话,根据实验结果来看:
版本 | 嵌套上限 | local变量上限 |
---|---|---|
LuaJIT | 325 | 65000 |
Lua5.3 | 4975 | 995000 |
测试的环境为macOS x86-64,LuaJIT方面无论JIT开启与否结果皆一致。根据前文所言来看,到了ARM环境这个数量将会进一步下降。虽然从对比来看差距有点大,但实际上在函数调用方面也算够用了。
模块级local变量
接下来便是我最关心的一点了:以上local变量上限是否会影响到模块级local变量?所谓模块级local变量即作用域为整个文件:
|
|
这种模块级local变量在Lua开发的应用还是很广泛的,它能有效的做到信息分隔的效果。但若是这些变量也受之前的上限规则影响,咁就扑街了!
首先是测试加载多个满载local变量的模块:
|
|
天可怜见,无论读取多少个文件,都不会存在上限问题。可见对于模块级local变量的处理是不一样的。到了这里基本上可以放心了,不过为防万一,我还做了模块的嵌套引用实验:
|
|
以这种形式生成了5000个文件,以此进行嵌套引用,结果也是成功通过了。由此可见,对于模块级local变量是可以放心地去使用了。
后记
尽管模块级local变量是可以随便用了,但是也要考虑到热更新方面的问题:若是选择使用模块级local变量去存储模块的数据,那么在热更新方面的处理将会变得十分麻烦。从这点考虑的话,模块级local变量最好只是用于引用别的模块为妙。