Lua 弱引用table

本文转载于:http://www.benmutou.com/archives/1808

 

这次要介绍的内容比较少,就一个——弱引用table

1.无法超越人类智慧的智能——自动内存管理的缺陷

我们都知道,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

这段代码有点复杂,智商低于250的可能会看不懂。

首先以一个table,叫做t。

然后创建一个新的table——key1,这个key1作为t的key值,给t新增了一个字段,赋值为1。

同样的,key2也作为t的一个key值。

 

接着,调用了collectgarbage函数,可以不管它,我们只要知道,它会让lua进行一次垃圾回收

最后输出t的所有字段,输出结果如下:

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

这很符合常理,也在我们的预计当中,虽然我们在给t赋值之后,key1和key2都赋值为nil了。

但是,已经添加到table中的key值是不会因此而被当做垃圾的。

换句话说,key1本身已经是nil值,但它曾经所指向的内容依然存放在t中。key2也是一样的情况。

所以我们最后还是能输出key1和key2的name字段。

 

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

刚刚举例的只是正常情况,那么,如果我们把某个table作为另一个table的key值后,希望当table设为nil值时,另一个table的那一条字段也被删除。

应该如何实现?

这时候就要用到弱引用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保持引用,所以t的key1字段也会被删除。

 

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执行垃圾回收的时候,并不一定是立刻生效的。

我们刚刚只是为了测试,而强制执行了垃圾回收

 

4.结束

好了,这次的内容比较少,其实书上有蛮多关于弱引用的例子的。

关于Lua的最基础部分,到这里算是结束了。

后面的内容是一些库的介绍,以及更深入的一些内容(C和Lua间调用、自定义类型、线程、内存管理)。

接下来可能会放缓文章更新速度,因为好多库的介绍,不知道有没有必要用文章记录下来。

可能而已~

转载于:https://www.cnblogs.com/guangyun/p/4685550.html

<think>好的,用户想了解Lua中强引用弱引用的区别及使用场景。首先,我需要回顾一下Lua中的引用机制。强引用是最常见的引用类型,只要存在强引用,对象就不会被垃圾回收器回收。而弱引用则不同,即使存在弱引用,如果对象没有其他强引用,垃圾回收时会被回收。 接下来,我得确认用户的问题重点。他们可能是在处理内存管理问题,或者遇到了对象无法释放的情况,想通过弱引用来优化内存使用。需要详细解释两者的区别,并举例说明使用场景,比如缓存、对象管理、监听器模式等。 还要注意Lua弱引用表的设置方式,通过元表的__mode字段,可以设置为"k"、"v"或"kv"。这部分需要具体说明,确保用户知道如何正确声明弱引用表。 另外,用户提供的引用资料中提到了弱引用表的使用和垃圾回收机制,需要将这些信息整合到回答中,确保引用正确。例如,引用[3]提到弱引用表不会增加引用计数,这需要强调。 最后,生成相关问题时要围绕Lua内存管理弱引用的具体实现和其他相关机制,比如元表的使用。确保问题对用户进一步学习有帮助。</think>### Lua引用弱引用的区别及使用场景 #### 一、核心区别 1. **强引用** - 对象被强引用时,其生命周期由引用计数决定 - 即使内存不足,只要有强引用存在,对象就不会被垃圾回收器(GC)回收 - 示例:普通表的键值对默认都是强引用 ```lua local strongTable = {} strongTable.key = {} -- 创建强引用关联 ``` 2. **弱引用** - 通过弱引用表(weak table)实现,需显式声明 - 不会阻止GC回收对象,当对象仅被弱引用时会被自动回收 - 声明方式:通过元表设置`__mode`字段 ```lua local weakTable = {} setmetatable(weakTable, {__mode = "k"}) -- 声明键为弱引用 ``` #### 二、技术特性对比 | 特性 | 强引用表 | 弱引用表 | |--------------|--------------------------|-----------------------------| | GC行为 | 阻止对象回收 | 允许对象回收[^3] | | 内存管理 | 需要手动解除引用 | 自动清理失效条目 | | 典型应用 | 常规数据存储 | 缓存/临时数据管理 | | 引用计数影响 | 增加引用计数 | 不影响引用计数[^3] | | 声明方式 | 默认 | 需设置元表`__mode`字段 | #### 三、使用场景 1. **缓存系统** 适合存储临时计算结果,当内存不足时自动释放旧缓存: ```lua local cache = {} setmetatable(cache, {__mode = "v"}) -- 值弱引用 function getBigData(id) if not cache[id] then cache[id] = computeExpensiveData(id) end return cache[id] end ``` 2. **对象管理** 管理临时对象时避免内存泄漏: ```lua local tempObjects = setmetatable({}, {__mode = "k"}) function createTempObject() local obj = {} tempObjects[obj] = true return obj end ``` 3. **监听器模式** 自动移除失效的监听器引用: ```lua local listeners = setmetatable({}, {__mode = "k"}) function addListener(target, callback) listeners[callback] = target end ``` #### 四、注意事项 1. `__mode`字段可选值: - `"k"`:键为弱引用 - `"v"`:值为弱引用 - `"kv"`:键值均为弱引用 2. 弱引用表条目会在GC时自动清除 3. 不应将系统关键对象存入弱引用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值