CHUAN2 DEV ENGINE
996 正版授权研发中心 · 360 授权合作教学中心 · 抖音传奇直播合作授权 · 快手推广运营商授权
OFFICIAL LICENSED ACADEMY 查验官方授权证书 →
// 威海旷世互娱教学基地 · 技术文章
Lua进阶性能调优

【Lua进阶】弱表 weak table:缓存与观察者的正确姿势

2026-09-20 07:58 作者:996 技术组 1 阅读 996引擎Lua教程传奇脚本
完整课程入口:996 全套课程体系Lua 学习路径幂尔框架 mirs.cn

强引用是默认,弱引用要声明

Lua 的 GC 判断"对象是否可回收"看的是引用:只要还有 table 拿着一个对象,它就不会被回收。这带来一个常见死结——你想给一堆对象挂附加数据(缓存计算结果、临时标记),用普通 table 存 cache[obj] = result,结果 obj 被别处销毁了,cache 还死死抓着它,内存永远降不下来。

弱表就是解药:把表的 __mode 元字段设为 "k"(key 弱)、"v"(value 弱)或 "kv",对应位置的引用不计入 GC 判定。对象一旦在其他地方都不可达,它在弱表里的条目会被自动清除。

lua
local cache = setmetatable({}, { __mode = "v" })  -- value 弱引用

cache[player] = computeExpensive(player)   -- 玩家对象销毁后
-- cache[player] 条目自动消失,无需手动清理

三个标准应用场景

第一,计算缓存。 给对象附加派生数据(战力值、格式化名称):用弱 value 表缓存,对象活着缓存有效,对象没了缓存自动蒸发,零维护成本。注意 key 用对象本身、value 放结果,而不是反过来。

第二,观察者与事件回调池。 事件总线若用强引用存监听者,忘记反注册就泄漏。把监听者表做成 __mode = "v" 的弱值表,销毁的对象自动从监听列表里蒸发,等于免费的自动反注册(前提是监听者没有其他强引用,用匿名闭包时要留全局句柄)。

第三,对象附加属性袋。 想给引擎传进来的 userdata/外部队象"贴标签"又不能改它的结构:用弱 key 表 attach[obj] = {...},生命周期与对象严格同生共死。

必须知道的行为细节

弱表的清理时机由 GC 决定:对象不可达后,条目要等下一轮回收才消失,期间访问可能仍拿到旧值——别把弱表当成"销毁通知器",销毁回调请走显式接口。其次,__mode = "k" 时数字 key 不会被弱化;值类型的数字、布尔、短字符串本身不受弱引用影响(它们不可被回收)。最后,弱表遍历中做增删可能拿到"将死"条目,遍历逻辑要对 nil 值保持宽容。

一个经验法则:给"别人的对象"挂数据用弱 key 表,给自己算的结果做缓存用弱 value 表。记住这句,弱表就不会用歪。

← 返回文章地图返回研学路径