Lua瞬表

Lua ephemeron table

Lua表中的键值对,在键或者值任何一方被回收时,都将从表中移除。

瞬表,特指键为弱引用值为强引用的表,它的值是否可达取决于键是否可达。如果瞬表的键仅被其值引用(即不可达,没有外部引用),键值对将被移除。这种设计符合直觉,当键不再可达时,也无法通过键取得值,键值对也不再有存在的意义。

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- Lua 5.4.2  Copyright (C) 1994-2020 Lua.org, PUC-Rio

function test(mode)
print("\n__mode:" .. mode)
local x = {}
print("x地址:", x)
local test = setmetatable({}, {__mode = mode})
test[x] = x
print(next(test))
print("取消x外部引用,并执行垃圾回收")
x = nil
collectgarbage()
print(next(test))
end

load("test('')")()
load("test('k')")()
load("test('v')")()
load("test('kv')")()

--[[
使用next遍历表的过程中的索引次序无定义(即使是数字索引),
给新键赋值是未定义行为,但可以修改已存在的键的值,也可以删除键
]]--

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
__mode:
x地址: table: 00000000006cacc0
table: 00000000006cacc0 table: 00000000006cacc0
取消x外部引用,并执行垃圾回收
table: 00000000006cacc0 table: 00000000006cacc0

__mode:k
x地址: table: 00000000006ca900
table: 00000000006ca900 table: 00000000006ca900
取消x外部引用,并执行垃圾回收
nil

__mode:v
x地址: table: 00000000006ca700
table: 00000000006ca700 table: 00000000006ca700
取消x外部引用,并执行垃圾回收
table: 00000000006ca700 table: 00000000006ca700

__mode:kv
x地址: table: 00000000006ca9c0
table: 00000000006ca9c0 table: 00000000006ca9c0
取消x外部引用,并执行垃圾回收
nil

可以看出,当test键为弱引用时,取消x外部引用会使test[x]被垃圾回收,无论值是否为强引用。

通过使用瞬表,可以在值为强引用的同时,由键的可达性决定值的可达性,从而避免循环引用使不可达对象无法被垃圾回收。


Lua瞬表
https://reddish.fun/posts/Article/Lua-ephemeron-table/
作者
bit704
发布于
2024年7月14日
许可协议