Appearance
垃圾回收
垃圾回收是 Lua 中自动管理内存的机制,它会自动回收不再使用的内存。本章节将介绍 Lua 中垃圾回收的基本原理和使用方法。
垃圾回收的基本原理
Lua 使用自动垃圾回收机制来管理内存。当一个值不再被任何变量引用时,它就会被垃圾回收器回收,释放占用的内存。
垃圾回收的触发时机
Lua 的垃圾回收器会在以下情况下触发:
- 当内存使用量达到一定阈值时
- 当显式调用
collectgarbage函数时
collectgarbage 函数
collectgarbage 函数用于控制垃圾回收器的行为:
lua
-- 强制进行一次垃圾回收
collectgarbage("collect")
-- 停止垃圾回收
collectgarbage("stop")
-- 重启垃圾回收
collectgarbage("restart")
-- 进行一次增量垃圾回收,返回未回收的内存大小
local bytes = collectgarbage("step")
-- 获取当前内存使用量
local bytes = collectgarbage("count")
-- 设置垃圾回收的阈值
collectgarbage("setpause", 100)
-- 设置垃圾回收的步进因子
collectgarbage("setstepmul", 200)垃圾回收的模式
Lua 5.2 及以上版本支持两种垃圾回收模式:
- 增量模式:垃圾回收过程分多个步骤进行,不会阻塞程序的执行
- ** generational 模式**:基于对象的生命周期进行垃圾回收,更高效
弱引用表
弱引用表是一种特殊的表,它不会阻止垃圾回收器回收表中的键或值:
弱引用键
lua
local weakKey = setmetatable({}, {__mode = "k"})
local key = {}
weakKey[key] = "value"
key = nil -- 键被设为 nil
collectgarbage("collect") -- 强制垃圾回收
for k, v in pairs(weakKey) do
print(k, v) -- 不会输出任何内容,因为键已被回收
end弱引用值
lua
local weakValue = setmetatable({}, {__mode = "v"})
local value = {}
weakValue["key"] = value
value = nil -- 值被设为 nil
collectgarbage("collect") -- 强制垃圾回收
for k, v in pairs(weakValue) do
print(k, v) -- 不会输出任何内容,因为值已被回收
end弱引用键和值
lua
local weakKeyValue = setmetatable({}, {__mode = "kv"})
local key = {}
local value = {}
weakKeyValue[key] = value
key = nil -- 键被设为 nil
value = nil -- 值被设为 nil
collectgarbage("collect") -- 强制垃圾回收
for k, v in pairs(weakKeyValue) do
print(k, v) -- 不会输出任何内容,因为键和值都已被回收
end垃圾回收的应用
示例 1:缓存
使用弱引用表可以创建一个自动清理的缓存:
lua
local cache = setmetatable({}, {__mode = "v"})
function getValue(key)
if cache[key] then
return cache[key]
end
local value = expensiveOperation(key)
cache[key] = value
return value
end示例 2:对象池
使用弱引用表可以创建一个对象池,自动回收不再使用的对象:
lua
local objectPool = setmetatable({}, {__mode = "v"})
function createObject()
for obj in pairs(objectPool) do
objectPool[obj] = nil
return obj
end
return {}
end
function releaseObject(obj)
-- 重置对象状态
for k in pairs(obj) do
obj[k] = nil
end
objectPool[obj] = true
end
-- 使用对象
local obj1 = createObject()
local obj2 = createObject()
-- 释放对象
releaseObject(obj1)
releaseObject(obj2)
-- 再次创建对象,会重用之前的对象
local obj3 = createObject()
local obj4 = createObject()
print(obj1 == obj3) -- 输出 true
print(obj2 == obj4) -- 输出 true示例 3:事件监听器
使用弱引用表可以创建一个自动清理的事件监听器系统:
lua
local listeners = setmetatable({}, {__mode = "k"})
function addListener(event, listener)
if not listeners[event] then
listeners[event] = setmetatable({}, {__mode = "k"})
end
listeners[event][listener] = true
end
function removeListener(event, listener)
if listeners[event] then
listeners[event][listener] = nil
end
end
function triggerEvent(event, ...)
if listeners[event] then
for listener in pairs(listeners[event]) do
listener(...)
end
end
end
-- 使用事件监听器
local listener = function(message)
print("收到消息:" .. message)
end
addListener("message", listener)
triggerEvent("message", "Hello, Lua!")
listener = nil -- 监听器被设为 nil
collectgarbage("collect") -- 强制垃圾回收
triggerEvent("message", "Hello again!") -- 不会输出任何内容,因为监听器已被回收垃圾回收的性能优化
- 减少表的创建:频繁创建和销毁表会增加垃圾回收的负担
- 使用对象池:重用对象而不是频繁创建新对象
- 合理设置垃圾回收参数:根据程序的特点调整
setpause和setstepmul参数 - 使用弱引用表:对于临时对象,使用弱引用表可以让垃圾回收器自动回收它们
- 避免循环引用:循环引用会导致垃圾回收器无法回收这些对象
循环引用的处理
Lua 的垃圾回收器可以处理循环引用:
lua
local a = {}
local b = {}
a.b = b
b.a = a
a = nil
b = nil
collectgarbage("collect") -- 强制垃圾回收
-- a 和 b 会被垃圾回收器回收小结
本章节介绍了 Lua 中垃圾回收的基本原理、触发时机、collectgarbage 函数、弱引用表和垃圾回收的应用。掌握这些内容,对于编写高效的 Lua 程序非常重要。