Lua 学习 chapter23
目录
- 弱引用表
- 记忆函数
- 对象属性
- 瞬表
- 析构器
- 垃圾收集器
- 控制垃圾收集的步长
只有疯狂过,你才知道自己究竟能不能成功。
弱引用表
弱引用表是用来告知lua语言一个引用不应该阻止对一个对象回收的机制。所谓弱引用是一种不在垃圾收集器考虑范围内的对象引用。如果一个对象都是所有的引用都是弱引用,那么垃圾回收器就可以回收这个对象,并把所有引用都删除了。
表是由键值对组成,一般情况下垃圾收集器不会回收一个在可访问表中作为值或者键的对象,键和值都是强引用。
在一个弱引用表中,键和值都可以是弱引用。所以这里就存在三种弱引用表,强键弱值,弱键强值以及弱键弱值这三种,不论是那种类型的弱引用表,只要有一个键或值被回收了,那么对应的整个键值对都会被从表中删除。
一个表是否为弱引用表是由原表中的__mode字段决定的,这个字段存在时,其值应该为一个字符串:这个字符串的值为”k”,那么表的键为弱引用,如果是”v”,值为弱应用,”kv”,表示这个表的键和值都是弱引用。
1
2
3
4
5
6
7
8
a = {}
mt = {__mode = "k"}
setmetatable(a, mt)
key = {}
a[key] = 1
key = {}
a[key] = 2
collectgarbage()--第一个key就被回收了
记忆函数
通过空间换时间,例如我们在迭代的时候,通过将已经迭代过得过程存下来,遇到相同的情况不需要再算了,直接返回结果。
但是如果有很多不同的迭代的话,运行时间够长的话,内存还是存在爆掉的情况,弱引用表为解决这种问题提供了一种简单的方案,如果results表具有弱引用的值,那么每个垃圾收集周期会删除所有那个时刻未使用的记录结果(基本上是全部)。
对象属性
弱引用表的另一个重要应用是将属性与对象关联起来。这样做的目的就是为了防止自身引用自己,然后一直不能被释放,这里我们需要使用的是弱引用的键。但是这里会存在一个问题,如果这个表的值也是弱引用,那么活跃的对象就有可能会被回收。
析构器
在lua中,一个具有弱引用的键和一个强引用的值的表是一个瞬表。在一个瞬表中,一个键的可访问控制着对应值的可访问性。更确切的说,考虑瞬表中的一个元素(k,v),指向的v的引用只有当存在某些执行k的其他外部引用存在时才是强引用,否则,即使v引用了k,垃圾回收器还是回收k的。
析构器
lua语言通过元方法__gc实现析构器。
1
2
3
4
o = { x = "hi"}
setmetatable(o, {__gc = function(o) print(o.x) end})
o = nil
collectgarbage() --hi
元函数__gc表示析构函数,在垃圾回收这个对象的时候会自动调用函数。
垃圾收集器
每一个垃圾回收周期由四个阶段组成:标记、清理、清除和析构。
- 标记阶段:把可达对象标记为活跃;
- 清理阶段: 处理析构器和弱引用表,这些没有被标记为活跃状态的对象会被标记为活跃(复苏),并放在一个单独的列表中,这个列表将在析构阶段使用。然后,lua遍历弱引用表并从中移除键或者值未被标记的元素。
- 清除阶段:遍历所有对象,对象未被标记为活跃就回收,否则标记为清理标记,然后准备下一个清理周期。
- 析构阶段:调用清理阶段被分离出来的对象的析构器。
控制垃圾回收的步长
通过函数collectgarbage可以对垃圾收集器进行一些额外的控制,该函数实际上是几个函数的集合体:第一个参数是一个可选的字符串,用来说明进行何种操作;有些选项使用一个整型作为第二个参数,称为data。
- “stop”:停止垃圾收集器,知道restart或再次调用collectgarbage。
- “restart”:重启垃圾收集器
- “collect”:执行一次完整的垃圾回收,回收和析构所有不可达的对象。这是默认的选项。
- “step”:执行某些垃圾收集工作,第二个参数data指明工作量,即在分配了data个字节后垃圾回收器应该做什么。
- “count”:以KB为单位返回当前已使用的内存数,该结果是一个浮点数,乘以1024得到的就是精确地字节数。该值包含了尚未被回收的死对象。
- “setpause”:设置收集器的pause参数(间歇率)。参数data以百分比为单位给出要设定的新值:当data为100时,参数被设为1(100%)
- “setstepmul”:设置收集器的stepmul参数(步进倍率,step multiplier).参数data给出新值,也是以百分比为单位
参数pause用于控制垃圾回收器再一次收集完成后扥待多久再开始新的一次收集,为0表示立即回收,200%表示内存使用翻倍后收集。一般应该把值控制在0到2之间。
参数stepmil控制对于每分配1KB内存,立即收集器应该进行多少工作。
<hr style="visibility: hidden;"/>
<hr style="visibility: hidden;"/>