弱引用table 《Lua程序设计》

>Lua的垃圾收集器只能回收那些它认为是垃圾的东西,不会回收用户认为是垃圾的东西。比如栈,栈由一个数组和一个顶部索引实现,如果弹出一个元素仅仅递减顶部索引,那么仍然停留在数组中的顶部对象,对Lua来说就不是垃圾。又比如存储在全局变量中的对象,即使程序不会再用它们,对Lua来说也不是垃圾。在这两种情况下,用户必须对对象变量赋值nil(t[i] = nil),才能释放它们。

>有时候,简单地清楚引用肯能够还不够,需要程序和gc进行更多的协作。例如,当一个对象处于数组中时,即使当前其他地方没有使用它,只要数组仍引用着它,它就无法被回收。也就是说,我们不想用t[i] = nil,也可以回收除了t引用外没有引用的对象。

>弱引用table(weak table)就是这么一种机制,用户用它告诉Lua这个table的引用不应该阻碍一个对象的回收。如果一个对象的所有引用都来自弱引用table,那么gc就可以回收这个对象了,并可以以某种形式来删除这些弱引用本身。

>table中有key和value,这两者都可以包含任意类型的对象。有3种弱引用table:具有弱引用key的table、具有弱引用value的table、同时具有弱引用key和弱引用value的table。无论哪种类型的弱引用table,只要有一个key或value被回收,那么它对应的整个key-value对都会从table中删除。

>table的弱引用类型通过元表中的__mode字段决定的,__mode是一个字符串,如果包含'k',key是弱引用的,如果包含'v',value是弱引用的,如果同时包含'k'和'v',key和value都是弱引用的。
a = {}
setmetatable(a, { __mode = "k" })
key = {}
a[key] = 1
key = {}
a[key] = 2
collectgarbage()    -- 强制进行垃圾回收
for k, v in pairs(a) do print(v) end    --> 2
第二个key值把第一个key值覆盖了,导致第一个key值没有被引用,导致强制垃圾回收时,被收回了。
key = nil
collectgarbage()
for k, v in pairs(a) do print(v) end  
  -->无输出,此时key变量也没有引用a原来的第二个key值,也导致被回收了。

>Lua只会回收弱引用table中的对象,像数字和布尔这样的“值”是不可回收的,字符串有些特殊,从实现的角度看,字符串是可以回收的,但从程序员的角度看,字符串就是值,而非对象,和数字和布尔一样,是不可回收的。

>备忘录(memoire)函数:
-- 用空间换时间,loadstring的时间成本很高,用一个辅助table记录下所有调用loadstring的结果。
local results = {}
function mem_loadstring (s)
    local res = results[s]
    if res == nil then   --是否记录过
        res = assert(loadstring(s))
        results[s] = res    -- 备以后用
    end
    return res
end
--改进:节省的时间非常客观,但results可能会把内存耗掉,弱引用table可以解决这个问题,让results具有弱引用的value即可。
local results = {}
setmetatable(results, { __mode = "v" })  -- 由于key是字符串,对弱引用table没有影响,所以完全可以用"kv"代替"v",不过有点画蛇添足了。
function mem_loadstring (s)
    local res = results[s]
    if res == nil then
        res = assert(loadstring(s))
        results[s] = res
    end
    return res
end
>“备忘录”技术还可以用来确保某类对象的唯一性。
function createRGB (r, g, b)
    return { red = r, green = g, blue = b }
end

--改进:复用具有相同颜色的table,备忘录table的key根据颜色分量生成。
local results = {}
setmetatable(results, { __mode = "v" })
function createRGB (r, g, b)
    local key = r .. "-" .. g .. "-" .. b
    local color = results[key]
    if color == nil then
        color = { red = r, green = g, blue = b }
        results[key] = color    -- 备以后用
    end
    return color
end
>弱引用table还可以将对象与属性关联起来。当对象没有其他引用时,Lua可以回收时,弱引用table中对应的键值对也会删除。
--用弱引用table将每个table与其默认值关联起来(第13章“元表与元方法”有提)。
local defaults = {}
setmetatable(defaults, { __mode = "k" })
local mt = { __index = function (t) return defaults[t] end {
function setDefault (t, d)
    defaults[t] = d
    setmetatable(t, mt)
end
--重复的默认值复用同样的元表,不同的默认值使用不同的元表(第13章“元表与元方法”有提)。
local metas = {}
setmetatable(metas, { __mode = "v" })
function setDefaults (t, d)
    local mt = metas[d]
    if mt == nil then
        mt = { __index = function () return d end}
        metas[d] = mt    -- 备以后用
    end
    setmetatable(t, mt)
end

第一种做法为每个table的默认值(defaults中的一个键值对)使用内存,第二种做法为每个不同的默认值(一个新table、一个新closure(if语句会产生closure???)和metas中的一个键值对)使用一组内存,如果程序有上千个table和一些默认值,采用第二种做法,如果只有很少的table或table的默认值很少相同的,采用第一种做法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值