weak table的定义:
(1)weak表是一个表,它拥有metatable,并且metatable定义了__mode字段;(2)weak表中的引用是弱引用(weak reference),弱引用不会导致对象的引用计数变化。换言之,如果一个对象只有弱引用指向它,那么gc会自动回收该对象的内存。
(3)__mode字段可以取以下三个值:k、v、kv。k表示table.key是weak的,也就是table的keys能够被自动gc;v表示table.value是weak的,也就是table的values能被自动gc;kv就是二者的组合。任何情况下,只要key和value中的一个被gc,那么这个key-value pair就被从表中移除了( In any case, if either the key or the value is collected, the whole pair is removed from the table)。
对于普通的强引用表,当你把对象放进表中的时候,就产生了一个引用,那么即使其他地方没有对表中元素的任何引用,gc也不会被回收这些对象。那么你的选择只有两种:手动释放表元素或者让它们常驻内存。
在lua中任何对内存块的引用都会使引用数加1,但有一个例外:weak table,它对内存块的引用不会使引用增1
看下面代码:
----------------------------------------------------
a = {};
b = {};
setmetatable(a, b); -- 设置a为weak table
b.__mode = 'k';
key = {}; -- 增加"{}"内存块的一个引用key,引用数1
a[key] = 1; -- weak table引用不增引数,所以"{}"内存块的引数还为1
key = {} -- 改变key指向新增的"{}"内存块,上面的"{}"内存块引数减一为0
a[key] = 2 -- 如上上一样
collectgarbage(); -- 调用GC,清掉weak表中没有引用的内存
for k, v in pairs(a) do
print(v); -- 只输出一个2
end
----------------------------------------------------
如果a不是weak table而是普通的table,那么a将会对"{}"内存块的引数加1,
去掉"b.__mode = 'k';"这句,你将会看到输出1和2。
看最后一个例子:
----------------------------------------------------
a = {}
b = {}
setmetatable(a, b) -- 设置a为weak table
b.__mode = "k"
function test()
local key1 = {};
a[key1] = 1;
local key2 = {};
a[key2] = 2;
end
test(); -- 函数执行完后key1和key2它们指向的内存块引数都减一为0
collectgarbage() -- 故全部都被清空
for k, v in pairs(a) do
print(v); -- 没有任何输出
end
----------------------------------------------------
设置弱引用为value
local testa = {}
local mt = {__mode = 'kv'}
setmetatable(testa,mt)
tbl_key = {1,2,3}
testa[1] = tbl_key
tbl_key = {4,5,6}
testa[2] = tbl_key
--垃圾回收
collectgarbage()
local function PrintInfo()
for k, v in pairs(testa) do
for key, value in pairs(v) do
print(" value===", value)
end
end
end
print(testa[1])
print(testa[2])
PrintInfo()