lua中垃圾回收机制、弱引用、__mode域元方法

垃圾回收机制(gc):

       lua使用自动内存管理机制,通过垃圾回收器来回收内存,垃圾回收器只能回收它认为是垃圾的内容,而不能回收用户认为是垃圾的内容,典型的例子---栈,栈一般用一个数组和一个表示顶部的索引值表示,如果弹出一个元素,那么仅是把栈顶索引减一,但这个元素还留在内存在被这栈数组引用着,所以垃圾回收器不知道它是垃圾,全局变量和table里的内容只能通过手动置为nil的方法来被垃圾回收器回收,因此需要一种与垃圾回收器可以协作的机制,lua里用弱引用table(weak table)来实现这个机制。

回收规则:
1.gc自动运行,也可以手动调用
2.自动收集的目标是引用计数为0的对象
3.dead objes:不能访问到的对象,没有引用指向它了,当然就是访问不到了,也就等同与垃圾内存了


弱引用table(弱表): 

        table的弱引用类型通过其元表中的__mode字段来决定,这个字段是一个字符串(table默认为强键强值),一张弱表可以有弱键或是弱值,也可以键值都是弱引用。 仅含有弱键的表允许收集器回收它的键,但会阻止对值所指的对象被回收。 若一张表的键值均为弱引用, 那么收集器可以回收其中的任意键和值。 任何情况下,只要键或值的任意一项被回收, 相关联的键值对都会从表中移除

1.{__mode='k'} 包含'k'则是key的弱引用,简称弱键

2.{__mode='v'} 包含'v'则是value的弱引用,简称弱值

3.{__mode='kv'} 都包含的则key、value都是弱引用(弱键弱值)

       对于普通的强引用表,当你把对象放进表中的时候,就产生了一个引用,那么即使其他地方没有对表中元素的任何引用,gc也不会被回收这些对象。那么你的选择只有两种:手动释放表元素(置为nil)或者让它们常驻内存。

strongTable = {}
strongTable[1] = function() print("i am the first element") end
strongTable[2] = function() print("i am the second element") end
strongTable[3] = {10, 20, 30}

print(table.getn(strongTable))            -- 3
collectgarbage()                        
print(table.getn(strongTable))            -- 3

弱键k的使用:

a = {}
b = {__mode = "k"}
setmetatable(a, b)
key = {name = "qq"} --key={}
a[key] = 1
key = {name = "ww"} --key={}
a[key] = 2
a[1] = 11 --number
a["aa"] = 22 --string
a[true] = 33 --boolean

collectgarbage() --强制进行一次垃圾收集
for k, v in pairs(a) do
    if type(k) == 'table' then
        print(k.name, v)
    else
        print(k, v)
    end
end
--打印信息
1   11
true    33
ww  2
aa  22

      将a表属性设置为弱键引用,key={name="qq"}相当于将key指向了{name="qq"},也可以称{name="qq"}被key所引用,随后a[key]=1,它的索引为一个table,理解为{name="qq"}对应的地址,当第二次对key进行赋值时,key由原来的指向{name="qq"}转为指向{name="ww"},这时{name="ww"}被key所引用,而原来的{name="qq"}并没有其他地方对它进行引用了,所以会被回收,所以相关联的键值会从表中移除,所以在打印的时候没有打印出{name="qq"}对应的值,但如果key是numberbooleanstring类型,则不会被回收上例中用table来当key,可以使用弱引用table来实现缓存等机制,热数据不会被回收,不用的数据自动释放

       值得注意的一点是,将上面代码中俩处key的赋值都改成key={}或者其他在数据上相等的表,也会按照相应流程进行回收,因为俩个{},也就是俩个表虽然数据上相等,但是俩个表的地址是不同的,所以在赋值之后,指向的位置是不同的,所以依然满足对应的逻辑流程

弱值v的使用:

       在编程环境中,有时你并不确定手动给一个键值赋nil的时机,而是需要等所有使用者用完以后进行释放,在释放以前,是可以访问这个键值对的。这种时候,weak表就派上用场了

weakTable = {}
weakTable[1] = function() print("i am the first element") end
weakTable[2] = function() print("i am the second element") end
weakTable[3] = {10, 20, 30}
weakTable[4] = 100 --值为number类型不会被回收
weakTable["aa"] = "aa" --值为string类型不会被回收
weakTable[true] = false --值为boolean类型不会被回收

setmetatable(weakTable, {__mode = "v"}) -- 设置为弱值表

for i, v in pairs(weakTable) do
    print(i, v)
end

ele = weakTable[1] -- 给索引为1的值增加一个引用
collectgarbage() -- 第一个函数引用为1,不能gc
print("~~~~~~~~~~~~~~~~~~~~~~~~~")
for i, v in pairs(weakTable) do
    print(i, v)
end

ele = nil -- 释放第一个函数的引用
collectgarbage()
print("~~~~~~~~~~~~~~~~~~~~~~~~~")

for i, v in pairs(weakTable) do
    print(i, v)
end
--打印信息
1   function: 00D6B7E0
2   function: 00D6BB00
3   table: 00D69548
4   100
aa  aa
true    false
~~~~~~~~~~~~~~~~~~~~~~~~~
1   function: 00D6B7E0
4   100
aa  aa
true    false
~~~~~~~~~~~~~~~~~~~~~~~~~
4   100
aa  aa
true    false

    当然在实际的代码过程中,我们不一定需要手动collectgarbage,因为该函数是在后台自动运行的,它有自己的运行周期和规律,对编程者来说是透明的

       注意:只有拥有显示构造的对象类型会被自动从weak表中移除,值类型booleannumber是不会自动从weak中移除的。而string类型虽然也由gc来负责清理,但是string没有显示的构造过程,因此也不会自动从weak表中移除,对于string的内存管理有单独的策略。

local a = {}
setmetatable(a, {__mode = 'v'})

key = {1, 2, 3}
a[1] = key --key设置为值 此时key引用{1,2,3}
key = {4, 5, 6} --改变k的值,key引用{4,5,6}
a[2] = key

--垃圾回收
collectgarbage()

for i, v in pairs(a) do
    print(i, v)
end

参考资料:
https://www.cnblogs.com/colin-chan/articles/4774651.html
https://www.cnblogs.com/sifenkesi/p/3850760.html

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值