collectgarbage("collect");--(垃圾收集释放内存)
local count = collectgarbage("count");--(垃圾统计所占内存)
print(">>>>>>>>>>>>>>>>>>>>>>>>>>count111 ",count);
local list = {};
for i = 1,100 do
local testList = {};
testList[1],testList[2] = 10000 + i,32 + i;
list[testList[1]] = testList[2];
end
print(">>>>>>>>>>>>>>>>>>>>>>>>>>count222 ",collectgarbage("count"));
--list = nil;
collectgarbage("collect");
print(">>>>>>>>>>>>>>>>>>>>>>>>>>count333 ",collectgarbage("count"));
从结果上看出,局部变量被回收了。list却没有被回收。当把list = nil时,请看下面结果。
当把list = nil时也会被collectgarbage(“collect”)给回收掉。
lua垃圾回收机制:
lua虽然会自己回收无用数据,但同时它还提供了回收函数——collectgarbage()。它的函数原型为:
collectgarbage(opt,[,arg])
其中opt参数有下面7种操作:
1、collectgarbage(“stop”):停止垃圾收集器的运行。 在调用重启前,收集器只会因显式的调用运行。
2、collectgarbage(“restart”): 如果垃圾收集器已经停止,将重新启动它。
3、collectgarbage(“collect”):执行一次全垃圾收集循环,默认执行此操作。
4、collectgarbage(“count”):以 K 字节数为单位返回 Lua 使用的总内存数。 这个值有小数部分,所以只需要乘上 1024 就能得到 Lua 使用的准确字节数(除非溢出)。
5、collectgarbage(“step”):单步运行垃圾收集器。 步长”大小”由 arg 控制。 传入 0 时,收集器步进(不可分割的)一步。 传入非 0 值, 收集器收集相当于 Lua 分配这些多(K 字节)内存的工作。 如果收集器结束一个循环将返回 true 。
6、collectgarbage(“setpause”):将 arg/100设为收集器的间歇率。返回 间歇率 的前一个值。默认为200。控制了收集器在开始一个新的收集周期之前要等待多久。 随着数字的增大就导致收集器工作工作的不那么主动。小于 1 的值意味着收集器在新的周期开始时不再等待。 当值为 2 的时候意味着在总使用内存数量达到原来的两倍时再开启新的周期。
7、collectgarbage(“setstepmul”): 返回 步进倍率 的前一个值。
作为步长的增幅(即新步长=旧步长*arg/100);并返回设置前的值。默认为200。控制了收集器的工作速度,这个速度是一个相对于内存分配的速度。更大的数字将导致收集器工作的更主动的同时,也使每步收集的尺寸增加。小于 1 的值会使收集器工作的非常慢,可能导致收集器永远都结束不了当前周期。
缺省值为200%,这意味着收集器将以内存分配器的两倍速运行。
总结一: 如何监测Lua的编程产生内存泄露:
1. 针对会产生泄露的函数,先调用collectgarbage(“count”),取得最初的内存使用
2. 函数调用后, collectgarbage(“collect”)进行收集, 并使用collectgarbage(“count”)再取得当前内存, 最后记录两次的使用差
3. 从test的收集可看到, collectgarbage(“collect”)被调用,并不保证一次成功, 所以, 大可以调用多次
**
总结二: 如何避免Lua应用中出现的内存使用过大行为:
**
1. 当然是代码实现不出现泄露
2. 在测试中,其实还发现, Lua中被分配的内存,其实并不会自动回收(个人估计要么就是Lua虚拟机没有做这个事情,要么就是回收的时机是在C层), 所以, 为了避免内存过大, 应用的运行时,可能需要定期的(调用collectgarbage(“collect”),又或者collectgarbage(“step”))进行显式回收。
**
## 【使用LUA开发游戏,发现内存耗费成倍增长】
**
内存随着时间成倍增加,这个感觉应该是和堆栈分配有关系,但是看我们LUA框架代码,大部分用到LUA地方都有进行释放了呀。。。
挨个对照COCOS2D-X提供的LUA框架和我们的LUA框架,发现在一般的方法,比如执行字符串,执行文件,等等ExecuteString,ExecuteScriptFile,ExecuteGlobalFunction函数写法都一样,于是范围缩小到我们自己写的几个函数里面。我们自己封装的执行对话框内部函数ExecuteTableFunction,GetTableFuntion等几个,仔细阅读代码后,终于发现问题了:
1)堆栈用完没有及时恢复
2)没有及时使用垃圾回收
解决方案
1)在函数异常返回或者正常处理返回时,堆栈要进行恢复:
lua_pop(L, 1);
// 恢复之前的栈顶位置
lua_settop(L, 0);
2)在调用lua_pcall()时,要调用lua_gc(L, LUA_GCCOLLECT, 0);进行垃圾回收;