弱表是是具有弱引用的表,如果只有弱引用,垃圾收集器会回收这些对象。弱表可以有弱键或者弱值,如果具有弱键,垃圾回收器会回收键不会回收值,反之亦然。弱表通过他的元表的__mode字段来控制到底属于弱键,弱值。
local mt = {__mode = "k"} --弱键
local weakTable = {}
--weakTable为弱表
setmetatable(weakTable,mt)
local key1 = {} --new一个空table1
local key2 = {} --new一个空table2
function printTb(tb)
print("--------------------------")
for k,v in pairs(weakTable) do
print("key ",k,"value ",v)
end
end
weakTable[key1] = 1
weakTable[key2] = 2
printTb(weakTable)
--把局部变量key1对table1引用解除
key1 = nil
--开始完整的gc,目前对table1的引用,只有weakTable
--因为weakTable为弱键的表,所以垃圾回收器会回收table1,
--table2因为还有个局部变量key2对其引用,所以垃圾回收器不会回收
collectgarbage()
printTb(weakTable)
--[[
最终打印结果 可以观察到table1会回收。
--------------------------
key table: 0x16819a0 value 1
key table: 0x1681ed0 value 2
--------------------------
key table: 0x1681ed0 value 2
]]
上面是一个弱键的例子,在看一个弱值的例子
local mt = {__mode = "v"} --弱键
local weakTable = {}
--weakTable为弱表
setmetatable(weakTable,mt)
local value1 = {} --new一个空table1
local value2 = {} --new一个空table2
function printTb(tb)
print("--------------------------")
for k,v in pairs(weakTable) do
print("key ",k,"value ",v)
end
end
weakTable[1] = value1
weakTable[2] = value2
printTb(weakTable)
value1 = nil --把局部变量value1对table1引用解除
--开始完整的gc,目前对table1的引用,只有weakTable
--因为weakTable为弱值的表,所以垃圾回收器会回收table1,
--table2因为还有个局部变量value2对其引用,所以垃圾回收器不会回收
collectgarbage()
printTb(weakTable)
--[[
最终打印结果 可以观察到table1会回收。
--------------------------
key 1 value table: 0x142e9a0
key 2 value table: 0x142eed0
--------------------------
key 2 value table: 0x142eed0
]]
“强值弱键”的弱表被称为ephemeron表,在表中,只有键可以被访问到才可以认为值可以被访问到,当只有键可以访问到值的时候,键值对会被移出(因为垃圾收集器回收了键)。如果把表模式从弱模式修改成普通模式在下一轮收集周期生效,所以本轮收集周期会回收部分。
弱表中只有explicit construction才会从弱表移出,比如值:numbers,和light c函数就不会收集。尽管字符串会被提交到垃圾收集器,但是因为没有explicit construction,所以字符串也不回从弱表移除。
local mt = {__mode = "v"} --弱键
local weakTable = {}
--weakTable为弱表
setmetatable(weakTable,mt)
local a = 100
local b = 101
local value1 = a
local value2 = b
function printTb(tb)
print("--------------------------")
for k,v in pairs(weakTable) do
print("key ",k,"value ",v)
end
end
weakTable[1] = value1
weakTable[2] = value2
printTb(weakTable)
value1 = nil
collectgarbage()
printTb(weakTable)
--[[最终打印结果
--------------------------
key 1 value 100
key 2 value 101
--------------------------
key 1 value 100
key 2 value 101
]]
查看部分反编译指令信息
; (06) local a = 100
004B 81C00000 [08] loadk 2 3 ; 100
; (07) local b = 101
004F C1000100 [09] loadk 3 4 ; 101
; (08) local value1 = a
0053 00010001 [10] move 4 2
; (09) local value2 = b
0057 40018001 [11] move 5 3
; (18) weakTable[1] = value1
0067 49000183 [15] settable 1 262 4 ; 1
; (19) weakTable[2] = value2
006B 49408183 [16] settable 1 263 5 ; 2
a,b分别在栈上,然后把常量表中的值move进a,b。
value1,value1也是move操作。值直接拷贝,不是指针的引用,所以number类型的值这里是不会被垃圾收集器回收掉。
弱表的应用,看到大部分的应用都是作为cache或者说记忆函数来使用,不用负责手动解引用释放表中pairs,会自动被gc。如果外部有对value的引用,那么gc的时候不会释放。
function makeCache()
return setmetatable({},{__mode = "kv"})
end
local cache = makeCache()
function getValue(key)
if cache[key] then
return cache[key]
else
cache[key] = loadstring("test")
return cache[key]
end
end
网友评论