关于Lua弱表中瞬表的测试

发布时间 2023-09-11 23:57:47作者: Fallever

关于Lua弱表中瞬表的测试


Lua手册中有个关于弱表中瞬表的细节:特别注意,如果表内的一个键仅仅被其值所关联引用,这个键值对将被表内移除
这个情况是用来处理循环引用的,测试如下

-- [[测试1
-- 新建2个对象
local x = {}
local y = {}

-- 使之循环引用
x.refY = y
y.refY = x

-- 打印地址
print("x:", x, "y:", y)
local test = {}
setmetatable(test, { __mode = "k" }) -- 现在test就是一个瞬表(暂时表)

test[x] = y -- 存入对象

print(next(test))

-- 去掉外部引用=> 局部变量不再直接或间接引用对象
x = nil
y = nil

--- 进行垃圾回收
collectgarbage()
print(next(test))
--OutPut:
> x:      table: 0000023E67AF7600 y:      table: 0000023E67AF7A00
> table: 0000023E67AF7600 table: 0000023E67AF7A00
> nil

由上例测试1可以看出,对于瞬表而言,当外部引用丢失,键只被值索引时,在垃圾回收时,弱引用可以处理循环引用的情况,弱引用被正常回收.

-- [[测试2
-- 新建2个对象
local x = {}
local y = {}

-- 使之循环引用
x.refY = y
y.refY = x

-- 打印地址
print("x:", x, "y:", y)
local test = {}
setmetatable(test, { __mode = "v" }) -- 不是瞬表

test[x] = y -- 存入对象

print(next(test))

-- 去掉外部引用=> 局部变量不再直接或间接引用对象
x = nil
y = nil

--- 进行垃圾回收
collectgarbage()
print(next(test))

--OutPut:
> x:      table: 0000023E67AF8140 y:      table: 0000023E67AF7480
> table: 0000023E67AF8140 table: 0000023E67AF7480
> table: 0000023E67AF8140 table: 0000023E67AF7480

测试2的代码与测试1除了 __mode='v',其他完全相同,由测试2可以看出,如果不是瞬表,在循环引用的情况下,弱引用不会被正常回收.

所以:

属性为弱键强值的表也被称为 暂时表。 对于一张暂时表, 它的值是否可达仅取决于其对应键是否可达。 特别注意,如果表内的一个键仅仅被其值所关联引用, 这个键值对将被表内移除。

PS: 之前在哪儿看到Lua解循环引用的办法,现在忘记了,如果有人看到过能在评论区贴一下就多谢了