Lua中的垃圾回收机制

来源:互联网 发布:计算机编程教学视频 编辑:程序博客网 时间:2024/05/16 15:22

遇到问题:
在运行lua脚本时,出现下面报错说内存不足:

>lua -e "io.stdout:setvbuf 'no'" "最大值最小值检查.lua" lua: not enough memory>Exit code: 1

原因是,lua解释器是32位的,它的内存大小只有2GB,当它内存不够时就会出现上述提示。lua语言虽然会自己回收释放掉的资源,但是,它的回收机制并不是实时回收的,而是,他会将脚本中无用了的变量进行标记,然后等到一个合适的机会进行回收。所以当循环次数特别多时,就有可能造成内存不足。

我们可以验证一下是否是这个原因:
我在代码循环中加入了 check.LogError(string.format("内存占用:%s", collectgarbage("count")))【后面介绍】,运行显示:

这里写图片描述
有上图可知,大概在内存占用 1737872.5029297KB(大概为1.7G左右)时 显示内存不足,所以上面的结论是正确的。其实lua中提供了垃圾回收函数——collectgarbage()。用户可以强制清除无用的垃圾数据。

所以,我在代码种每次for循环一次强行清理一次垃圾:

--for循环每循环一次调用该函数清理一次垃圾function MemoryCollect()    if collectgarbage("count") > 1500000 then        check.LogError(string.format("内存占用已接近临界值,请注意修改用例:%s", collectgarbage("count")))        collectgarbage("collect")        check.LogError("内存清理成功")    endend!

这里写图片描述

脚本运行成功。

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. 从test1的收集可看到, collectgarbage(“collect”)被调用,并不保证一次成功, 所以, 大可以调用多次

避免Lua应用中出现的内存使用过大行为:
1. 防止代码出现泄露
2. 其实,Lua中被分配的内存,并不会及时的自动回收, 所以, 为了避免内存过大, 应用的运行时,可以定期的(调用collectgarbage(“collect”),又或者collectgarbage(“step”))进行显式回收。