1.使用局部变量local
这是最基础也是最有用的策略,虽然使用全局变量并不能完全避免,但还是应该尽量避免,取而代之使用局部变量即local
。这里的局部变量也包括函数function
,因为在Lua里函数也是一个变量。局部变量的存取会更快,而且在生命周期之外就会释放掉。
使用全局变量
CCX = display . contentCenterX --global variable
for i = 1 , 100 do
local image = display . newImage ( " myImage" )
image . x = CCX
end
使用局部变量
local CCX = display . contentCenterX --local variable
for i = 1 , 100 do
local image = display . newImage ( " myImage" )
image . x = CCX
end
这个原则也适用于Lua的核心库,比如math
库。对于这类函数也应该使用局部变量。
非局部变量
local function foo ( x )
for i = 1 , 100 do
x = x + math.sin ( i )
end
return x
end
使用局部变量
local sin = math.sin --local reference to math.sin
local function foo ( x )
for i = 1 , 100 do
x = x + sin ( i )
end
return x
end
最后,记住尽量用局部变量的方式来使用函数。当然,这样需要注意函数的作用域的问题。如果你对Lua的作用域还不够清楚,请看Understanding “SCOPE” for beginning programmers 。
2.避免将函数体定义作为其他函数的参数来使用
如果函数的参数是函数时,应将参数函数作为局部变量传进参数,而不要直接写函数定义,请看下面两个例子:
直接在参数表里定义函数
local func1 = function ( a , b , func )
return func ( a + b )
end
for i = 1 , 100 do
local x = func1 ( 1 , 2 , function ( a ) return a * 2 end )
print ( x )
end
使用局部变量传参 -- local 标记的函数或变量只能用在当前作用域,如果函数参数是传递给其他类或文件的,请不要贪图这丁点效率
local func1 = function ( a , b , func )
return func ( a + b )
end
local func2 = function ( c )
return c * 2
end
for i = 1 , 100 do
local x = func1 ( 1 , 2 , func2 )
print ( x )
end
3.避免使用table.insert()
下面来看看4个实现表插入的方法。在4个方法之中table.insert()
在效率上不如其他方法,是应该避免使用的。
使用table.insert
local a = {}
local table_insert = table.insert
for i = 1 , 100 do
table_insert ( a , i )
end
使用循环的计数
local a = {}
for i = 1 , 100 do
a [ i ] = i
end
使用table的size
local a = {}
for i = 1 , 100 do
a [ # a + 1 ] = i
end
使用计数器
local a = {}
local index = 1
for i = 1 , 100 do
a [ index ] = i
index = index + 1
end
4.减少使用 unpack()
函数
Lua的unpack() 函数不是一个效率很高的函数。你完全可以写一个循环来代替它的作用。
使用unpack()
local a = { 100 , 200 , 300 , 400 }
for i = 1 , 100 do
print ( unpack ( a ) )
end
代替方法
local a = { 100 , 200 , 300 , 400 }
for i = 1 , 100 do
print ( a [ 1 ], a [ 2 ], a [ 3 ], a [ 4 ] )
end
5.缓存table的元素
缓存table的元素,特别是在循环内使用会提高效率。
未缓存
for i = 1 , 100 do
for n = 1 , 100 do
a [ n ]. x = a [ n ]. x + 1
print ( a [ n ]. x )
end
end
缓存 -- 只适合引用类型,而对于值类型只适合读取数据不能存储新值
for i = 1 , 100 do
for n = 1 , 100 do
local y = a [ n ]
y . x = y . x + 1
print ( y . x )
end
end
6.避免使用ipairs()
当遍历table时,使用Lua的ipairs() 的效率并不高。
使用ipairs() -- 对于非顺序数字索引的只能用pairs()
local t1 = {}
local t2 = {}
local t3 = {}
local t4 = {}
local a = { t1 , t2 , t3 , t4 }
for i , v in ipairs ( a ) do
print ( i , v )
end
代替方法
local t1 = {}
local t2 = {}
local t3 = {}
local t4 = {}
local a = { t1 , t2 , t3 , t4 }
for i = 1 , # a do
print ( a [ i ] )
end
7.数学方法的效率比较
应该使用更快的数学方法。
避免对正数使用math.fmod()
--math.fmod method (discouraged)
local fmod = math.fmod
for i = 1 , 100 do
if ( fmod ( i , 30 ) < 1 ) then
local x = 1
end
end
--modulus operator method (recommended)
for i = 1 , 100 do
if ( ( i % 30 ) < 1 ) then
local x = 1
end
end
乘法比除法快
x * 0.5 ; x * 0.125 --recommended
x / 2 ; x / 8 --discouraged
乘法比乘幂快
x * x * x --recommended
x ^ 3 --discouraged
8.保存Texture内存
Texture内存一般只有在出现警告时才会去关注,但那时就很难去补救了。
当texture不需要的时候记得释放掉。 如果你有一个525×600的背景图片,你可以改成448×512的。因为OpenGL对图片内存遵循2的倍数原则,即每次使用内存都是以2的倍数为长度的。所以525×600的图片将会消耗1024*1024的内存(即1024×1024 (pixels) × 4 (bytes) = 4,194,304 bytes = 4 MB),而448×512只会消耗1/4的内存。在图片清晰度容忍的情况下尽量缩小到下一个2倍量级内。 尽可能的重复利用素材。对于图片相同而颜色不同的可以使用setFillColor 函数。例如你有红苹果和青苹果,那么你可以创建一个灰度的图片然后分别添加红色和绿色。 如果你使用image sheet,那么一定要使用类似TexturePacker 的软件,不仅能提高开发效率也能优化图片大小。
9.预先创建物理对象
如果你要在场景中使用一定数量的物理对象,那么预先创建所有的对象会在使用时提高效率。那些暂时用不到的对象可以设置为未激活的状态然后放到屏幕的外面或者放到一个不可见的group里。当需要时设置对于的位置并激活即可。 实时创建物理对象并不是不可以,但一次性创建10-20个对象必然会造成性能问题,而导致顿卡延时等。 当然,也要考虑到内存的问题,如果一开始就创建几百个物体,那么对于内存的消耗就使得性能提高有点得不偿失了。
10.音频使用策略
有些音效是整个app都会用到的,这样的音效需要一开始就载入到内存中。对于音质并没有特别高的要求的音乐和音效需要考虑是否需要压缩,比如使用11khz来减小音频文件的大小,一般用户也听不出太大的区别,而这样减少的内存可是相当可观的。而且要使用简单的适合多平台的音频格式,比如WAV格式。 如果需要的话,音效可以如下组织成一个table,这样便于在使用时引用或者在不需要的时候释放掉。
--load these sounds during NON-time-critical code
local soundTable = {
mySound1 = audio . loadSound ( " a.wav" ),
mySound2 = audio . loadSound ( " b.wav" ),
mySound3 = audio . loadSound ( " c.wav" ),
mySound4 = audio . loadSound ( " d.wav" ),
mySound5 = audio . loadSound ( " e.wav" ),
mySound6 = audio . loadSound ( " f.wav" ),
mySound7 = audio . loadSound ( " g.wav" ),
mySound8 = audio . loadSound ( " h.wav" ),
}
播放一个音效就非常简单:
local mySound = audio . play ( soundTable [ " mySound1" ] )
永远不要忘记,当音效不需要的时候就要释放掉:
local ST = soundTable
for s , v in pairs ( ST ) do
audio . dispose ( ST [ s ] ) ; ST [ s ] = nil
end
另外,引用百度知道上@wydwuf 的话:
用lua之类的脚本语言编程,本来就不用考虑太多所谓效率,要效率用C去。
尤其是在lua 里,local的最本质作用就是我说的 "数据/接口隐藏和防止全局名称冲突"。
你去看看 lua 的语言标准,哪一句告诉你要因为效率而使用 local?
用不用 local 只和你具体的任务有关,和效率有什么关系?
原文:
lua使用优化建议