学习Cocos2d-x Lua:Lua基础之弱引用table

2015年03月25日 11:19 0 点赞 0 评论 更新于 2025-11-21 18:30

在这个系列中,我们将深入学习Cocos2d-x Lua,总结Lua开发过程中涉及的知识点,以及如何在开发过程中使用Cocos Code IDE。本篇文章将重点讲解引用table的相关问题。

1. 自动内存管理的缺陷

Lua具备自动内存管理机制,不过可能有些朋友对此并不了解。在Lua中,我们只需创建对象,无需手动删除对象(对于不再需要的对象,将其设置为nil即可),Lua会自动删除被判定为垃圾的对象。

然而,问题在于,Lua有时无法准确识别哪些对象是垃圾对象。例如,以下代码:

t = {};
-- 使用一个table作为t的key值
key1 = {name = "key1"};
t[key1] = 1;
key1 = nil;

-- 又使用一个table作为t的key值
key2 = {name = "key2"};
t[key2] = 1;
key2 = nil;

-- 强制进行一次垃圾收集
collectgarbage();

for key, value in pairs(t) do
print(key.name .. ":" .. value);
end

上述代码的执行逻辑如下:首先创建一个名为t的table,接着创建一个新的tablekey1,并将其作为t的key值,为t新增一个字段并赋值为1。同样,key2也作为t的一个key值。之后,调用collectgarbage函数,该函数会触发Lua进行一次垃圾回收。最后,输出t的所有字段,输出结果如下:

[LUA-print] key1:1
[LUA-print] key2:1

这一结果符合预期,尽管在给t赋值之后,key1key2都被赋值为nil,但已经添加到table中的key值不会因此被当作垃圾。也就是说,key1本身虽已为nil,但其曾经指向的内容依然存于t中,key2的情况也是如此,所以最终仍能输出key1key2name字段。

2. 颠覆认知——弱引用table

上述示例为正常情况,若我们希望在将某个table作为另一个table的key值后,当该table被设为nil时,另一个table对应的字段也被删除,该如何实现呢?这时就需要用到弱引用table,其实现借助了元表。

以下代码与前面的示例几乎相同,仅新增了一行代码:

t = {};
-- 给t设置一个元表,增加__mode元方法,赋值为“k”
setmetatable(t, {__mode = "k"});

-- 使用一个table作为t的key值
key1 = {name = "key1"};
t[key1] = 1;
key1 = nil;

-- 又使用一个table作为t的key值
key2 = {name = "key2"};
t[key2] = 1;
key2 = nil;

-- 强制进行一次垃圾收集
collectgarbage();

for key, value in pairs(t) do
print(key.name .. ":" .. value);
end

需要注意的是,在t创建后,立即为其设置了元表,元表中有一个__mode字段,赋值为字符串"k"。运行这段代码,会发现没有任何输出,因为t的所有字段都已不存在。

这就是弱引用table的一种形式,为table添加__mode元方法,若该元方法的值包含字符串"k",则表示这个table的key都是弱引用的。一旦其他地方对key值的引用取消(设置为nil),那么这个table里对应的字段也会被删除。

通俗来讲,由于t的key被设置为弱引用,执行t[key1] = 1后,t中确实存在该字段。随后执行key1 = nil,此时除了t本身外,没有其他地方对key1保持引用,所以tkey1字段也会被删除。

3. 三种形式的弱引用

弱引用table有以下三种形式:

  1. key值弱引用:即上述所讨论的情况,只要其他地方没有对key值进行引用,那么table自身的该字段也会被删除。设置方法为:setmetatable(t, {__mode = "k"});
  2. value值弱引用:情况类似,只要其他地方没有对value值进行引用,那么table中该value所在的字段也会被删除。设置方法为:setmetatable(t, {__mode = "v"});
  3. key和value弱引用:规则相同,但key和value同时生效,任意一个条件满足时都会导致table的字段被删除。设置方法为:setmetatable(t, {__mode = "kv"});

需要注意的是,这里所说的“被删除”,是指在Lua执行垃圾回收时,并不一定立即生效。我们之前的测试是为了验证效果而强制执行了垃圾回收。

作者信息

boke

boke

共发布了 3994 篇文章