lua-弱表

2019-04-28  本文已影响0人  Teech

弱表是是具有弱引用的表,如果只有弱引用,垃圾收集器会回收这些对象。弱表可以有弱键或者弱值,如果具有弱键,垃圾回收器会回收键不会回收值,反之亦然。弱表通过他的元表的__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
上一篇下一篇

猜你喜欢

热点阅读