Lua 垃圾回收:collectgarbage() 函数
Lua 使用自动内存管理,通过垃圾回收(Garbage Collection, GC)机制释放不再使用的对象。你无需手动释放内存,但可通过内置函数 collectgarbage() 主动干预回收过程,优化程序性能或调试内存问题。
什么是 collectgarbage()?
collectgarbage() 是 Lua 提供的控制垃圾回收器的核心函数。它允许你触发回收、查询状态、调整参数等。该函数接受一个字符串参数指定操作类型,并可选地传入第二个参数作为附加值。
调用格式为:
collectgarbage("option", arg)
其中 "option" 决定执行哪种操作,arg 是可选数值(仅部分选项需要)。
常用操作详解
-
"collect":立即执行一次完整垃圾回收
执行collectgarbage("collect")会强制 Lua 运行完整的垃圾回收周期,清理所有不可达对象。这是最常用的操作,适合在已知大量临时对象被创建后手动释放内存。 -
"stop":暂停垃圾回收器
执行collectgarbage("stop")会让 GC 停止自动运行。此后除非显式调用回收,否则内存不会被清理。适用于需要精确控制内存分配时机的场景(如实时系统),但需谨慎使用,避免内存泄漏。 -
"restart":恢复自动垃圾回收
执行collectgarbage("restart")可重新启用被暂停的 GC。Lua 启动时默认处于运行状态,此操作主要用于恢复因"stop"而暂停的回收器。 -
"count":获取当前内存使用量(KB)
执行local kb = collectgarbage("count")返回 Lua 当前占用的内存总量(单位为千字节)。注意:返回值是浮点数,小数部分表示不足 1KB 的字节数(例如1024.5表示 1024 KB + 512 字节)。 -
"step":执行一步增量回收
执行collectgarbage("step", size)让 GC 执行一步工作,size是“预算”(以 KB 为单位,实际内部使用的是虚拟字节数)。若该步完成整个回收周期,则返回true;否则返回false。适合在帧循环中分摊回收开销,避免卡顿。 -
"setpause":设置回收器暂停比例
执行collectgarbage("setpause", value)调整 GC 在两次回收之间的等待时间。value是百分比(默认 200),表示“当内存增长到上次回收后大小的value/100倍时,才启动下一次回收”。增大该值可减少回收频率,降低 CPU 开销,但可能增加峰值内存。 -
"setstepmul":设置回收步进速度
执行collectgarbage("setstepmul", value)控制增量回收每一步的工作量。value是倍数(默认 200),表示“每分配 1 单位内存,GC 执行value/100单位的回收工作”。增大该值使回收更快完成,减少内存占用,但会增加单次开销。
实用技巧与注意事项
-
不要频繁调用
"collect":虽然能立即释放内存,但完整回收代价较高,可能造成程序卡顿。仅在明确知道有大量临时对象被丢弃后使用(如关卡切换、大文件处理完毕)。 -
监控内存变化:结合
"count"定期检查内存,有助于发现内存泄漏。例如:local before = collectgarbage("count") -- 执行某段代码 local after = collectgarbage("count") print("内存增长:", after - before, "KB") -
增量回收更适合游戏或实时应用:使用
"step"在每帧中执行少量回收,避免长时间停顿。例如每帧调用collectgarbage("step", 10),预算设为 10KB。 -
调整参数需测试验证:
"setpause"和"setstepmul"的默认值对大多数应用已足够平衡。修改前应通过实际负载测试,观察内存与 CPU 的权衡。 -
回收器状态不影响程序逻辑:无论 GC 是否运行,Lua 的语义保证一致——不可达对象终将被回收。手动控制仅用于性能优化,而非正确性保障。
参数对照表
以下表格总结了 collectgarbage() 各选项的功能、是否需要第二参数、返回值及典型用途。
选项 ("option") |
需要 arg? |
返回值 | 典型用途 |
|---|---|---|---|
"collect" |
否 | 无 | 强制完整回收,释放内存 |
"stop" |
否 | 无 | 暂停自动回收 |
"restart" |
否 | 无 | 恢复自动回收 |
"count" |
否 | number(内存 KB) | 监控内存使用量 |
"step" |
是 | boolean(是否完成周期) | 增量回收,避免卡顿 |
"setpause" |
是 | 无 | 调整回收频率 |
"setstepmul" |
是 | 无 | 调整回收速度 |
示例:安全地释放大表
假设你有一个临时生成的大表 temp_data,使用完毕后希望尽快释放其内存:
-- 创建大量数据
local temp_data = {}
for i = 1, 100000 do
temp_data[i] = {x = i, y = i * 2}
end
-- 使用完毕后清空引用
temp_data = nil
-- 主动触发回收
collectgarbage("collect")
关键点:先将变量设为 nil 切断引用,再调用 "collect"。若不设 nil,表仍被引用,无法被回收。
高级用法:自定义回收策略
在嵌入式或资源受限环境中,可完全接管回收节奏:
-- 启动时暂停自动回收
collectgarbage("stop")
-- 在主循环中每帧执行小步回收
while running do
update_game_logic()
-- 每帧预算 5KB 回收工作
collectgarbage("step", 5)
end
-- 程序退出前彻底清理
collectgarbage("restart")
collectgarbage("collect")
此模式确保 GC 开销均匀分布,避免突发性延迟。
调用 collectgarbage("collect") 是最直接的内存释放手段,但应理解其代价;使用 "step" 配合合理预算可实现平滑回收;监控 "count" 有助于诊断内存问题;调整 "setpause" 与 "setstepmul" 可在特定场景优化性能。掌握这些操作,即可在需要时精准控制 Lua 的内存行为。

暂无评论,快来抢沙发吧!