lua中的弱表

弱表 指内部元素为 弱引用 的表。 垃圾收集器会忽略掉弱引用。 换句话说,如果一个对象只被弱引用引用到, 垃圾收集器就会回收这个对象。

lua的弱表使用,分为弱键和弱值。均是对table类型才起作用。基本类型,number,bool,string都不受此影响。

下面直接上代码。

弱键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
testObj = {}
setmetatable(testObj, {__mode = "k"})

local key = {name = "hello,world1"}
testObj[key] = 1
key = {name = "hello,world2"}
testObj[key] = 2
testObj[1] = 1 --number
testObj["string"] = "字符串" --string
testObj[true] = true --boolean


dump(testObj)
print("============强制进行一次垃圾收集======")
collectgarbage() --强制进行一次垃圾收集
print("============现在的表中数据======")
dump(testObj)

输入的结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dump from: /Users/JolieHou/ct/test2.lua:95: in main chunk
- "<var>" = {
- 1 = 1
- "string" = "字符串"
- table: 0x7fb324d04700 = 1
- table: 0x7fb324d04780 = 2
- true = true
- }
============强制进行一次垃圾收集======
============现在的表中数据======
dump from: /Users/JolieHou/ct/test2.lua:99: in main chunk
- "<var>" = {
- 1 = 1
- "string" = "字符串"
- table: 0x7fb324d04780 = 2
- true = true
- }
[Finished in 0.0s]

从上面的输出,不难看出以下几点:

  1. 弱键只对table起作用。基本类型string,number,bool不受此影响。
  2. {name = "hello,world1"} 这个table一开始被key引用。接下来key又引用了{name = "hello,world2"},因此{name = "hello,world1"}这个table就没有人引用,相当于引用计数为0,因此在垃圾回收之后,{name = “hello,world1”}就被回收了。正如上面所言。
  3. 之所以垃圾回收之后,{name = "hello,world2"}还存在于testObj中,正是由于key这个变量的引用。假设我们把key=nil,结果会怎样?你猜。结果如下:
1
2
3
4
5
6
- "<var>" = {
- 1 = 1
- "string" = "字符串"
- true = true
- }
[Finished in 0.0s]

弱值

弱值和弱键是一样的。如果对应的值是table,并且table没有人应用,那么在垃圾回收触发之后就直接回收了。
上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
testObj = {}
setmetatable(testObj, {__mode = "v"})

key = {name = "hello,world"}
testObj[key] = {name = "hello,world1"}
key = {name = "hello,world"}
testObj[key] = {name = "hello,world2"}
value = testObj[key]

dump(testObj)
print("============强制进行一次垃圾收集======")
collectgarbage() --强制进行一次垃圾收集
print("============现在的表中数据======")
dump(testObj)

此时打印日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dump from: /Users/JolieHou/ct/test2.lua:92: in main chunk
- "<var>" = {
- table: 0x7fc6a5c0af10 = {
- "name" = "hello,world1"
- }
- table: 0x7fc6a5c0af90 = {
- "name" = "hello,world2"
- }
- }
============强制进行一次垃圾收集======
============现在的表中数据======
dump from: /Users/JolieHou/ct/test2.lua:96: in main chunk
- "<var>" = {
- table: 0x7fc6a5c0af90 = {
- "name" = "hello,world2"
- }
- }
[Finished in 0.0s]

上面代码,在一次垃圾回收之后,testObj中只剩下了hello,world2.为何呢?关键就是上面的value = testObj[key],就是value对表值的一次引用。只要value一直存活,hello,world2相当于有人引用,就不会被回收。

结论

原来弱表是这么简单!这样我们就不用想着去释放资源了,对不对。很方便?正是由于这个太灵活了,一旦触发就会,可能会出现空指针错误。所以综合考虑,尤其是团队协作的时候。