使用弱表的目的是优化垃圾的自动回收。
一、垃圾回收
lua的垃圾回收算法为 标记清除法(Mark and Sweep),具体可查GC的三大基础算法。
1、垃圾收集器GC可以自动执行也可以手动设置collectgarbage()
2、对象符合可自动回收的两个条件
1、对象本身为可回收类型
2、无引用或只有弱引用(全局声明的变量存储在lua的全局表中,不会被自动回收)
二、弱表
弱表是一个表且拥有metatable
元表,并在metatable
中定义了__mode
字段。
一个表的弱引用类型是通过其元素的__mode
模式字段来决定的,__mode
模式的值是一个字符串,如果字符串中包含字母k,
则这个表的key
键名是弱引用。如果字符串中包含字母v
则表的value
键值是弱引用的。
__mode字段取值可分为k、v、kv
k表示table.key是weak的,也就是table的keys是能够被垃圾收集器自动回收。
v表示table.value是weak的,也就是table的values能够被垃圾收集器自动回收。
kv是二者的组合,任何情况下只要key和value中的一个被垃圾收集器自动回收,那么kv键值对就被从表中移除。
三、代码示例
1、赋值引用
local weakTbl = {
"dasdasd",
{dd = "dddd"},
}
setmetatable(weakTbl,{
__mode = "v",
})
-- local dan = weakTbl[2] -- 此处为强引用 执行后weakTbl[2]将不会被回收
collectgarbage()
for k,v in pairs(weakTbl) do
print(k, v)
end
输出:
1 dasdasd
取消注释后输出为:
1 dasdasd
2 table: 01402FF0
2、对象被表的key引用
local tbl = {}
local mt = {__mode = "k"}
setmetatable(tbl, mt)
local key = {count = 100}
tbl[key] = 2
-- key = {} -- 此处重新赋值 导致原key存储的地址 现在只有弱表tbl引用
-- 强制垃圾收集
collectgarbage()
print("log print: ")
for k,v in pairs(tbl) do
print(k, v, k.count) -- table: 00000000001f9730 2 nil
end
输出:
log print:
table: 00873568 2 100
取消注释后输出为:
log print:
总结
弱表和弱引用就是为了告诉GC回收器,对象此处为弱引用,是不影响回收的。