首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Lua 內存洩露檢測原理與垃圾回收機制深度解析

     編輯:關於C++

Lua 內存洩露的本質

Lua 擁有自動垃圾回收(GC),理論上無傳統意義的內存洩露。此處的「洩露」指:對象已不再使用,但仍被外部引用(如全局表 _G、註冊表、metatable)導致 GC 無法回收。

例:函數內忘記 local 聲明表,導致其進入 _G,函數結束後引用仍存,GC 掃描到引用不回收。

GC 可掃描的根對象

Lua 支援 GC 的類型:string、table、function、full userdata、thread。它們的引用直接或間接保存在:

  • lua_state 對象(腳本本身)
  • _G 全局表
  • Registry 註冊表(debug.getregistry() 可訪問)
  • global_state->mt 中的 metatable(debug.getmetatable() 可訪問)

腳本層檢測流程

  1. 運行前執行多次 collectgarbage("collect"),遍歷上述根對象,記錄所有可達對象的初始快照。
  2. 運行目標代碼。
  3. 再次強制 GC 並遍歷,對比兩次快照,新增且未被業務邏輯釋放的對象即為疑似洩露。

遍歷時的特殊處理

  • table:需額外遍歷 metatable;若 metatable 有 __mode = "k"/"v"/"kv"(弱引用),對應鍵/值不阻止 GC。
  • function:需遍歷 upvalues(可為任意類型)與 environment(table)。
  • userdata:腳本層不可修改,僅檢查其 metatable。
  • thread:獲取其主函數,按 function 處理。

弱表應用:資源洩露自動檢測

將用戶創建的資源對象放入 __mode="v" 的弱表。運行後強制 GC,若弱表中對象仍存在,說明外部有強引用,疑似洩露。

Lua GC 算法:增量標記-清掃

三色標記法:

  • 白:未掃描
  • 灰:已掃描,但關聯對象未掃描
  • 黑:自身及關聯對象均已掃描

增量式執行,避免長時間停頓。

collectgarbage 常用選項

選項說明
"stop"停止 GC
"restart"重啟 GC
"collect"執行完整 GC 循環(默認)
"count"返回當前內存使用(KB)
"step"單步執行 GC,參數控制步長
"setpause"設置暫停倍率(默認 200,即內存翻倍觸發新循環)
"setstepmul"設置步長倍率(默認 200,GC 速度為分配速度 2 倍)

代碼示例:觀察局部/全局變量 GC 行為

function testLocal()
    collectgarbage("collect"); collectgarbage()
    print("初始:", collectgarbage("count"))
    local t = {} for i=1,5000 do t[i]={} end
    print("創建後:", collectgarbage("count"))
end

function testGlobal()
    collectgarbage("collect"); collectgarbage()
    print("初始:", collectgarbage("count"))
    g = {} for i=1,5000 do g[i]={} end
    print("創建後:", collectgarbage("count"))
end

testLocal(); collectgarbage(); collectgarbage(); print("Local GC後:", collectgarbage("count"))
testGlobal(); collectgarbage(); collectgarbage(); print("Global GC後:", collectgarbage("count"))
-- Local 內存歸零,Global 內存殘留(洩露)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved