利用 Lua 的垃圾回收器(GC)與弱表特性,輔助 C++ 實現引用計數智能指針,並在運行期監控對象生命週期,自動報告未釋放內存。
RefCounted 基類(虛構造、addRef/release)、IntrusivePtr<T> 智能指針模板。registry["__cpp_objects"] = 弱鍵表 { [cpp_ptr] = true }__gc 元方法:檢測 C++ 對象引用計數是否為 0,否則報警sol2 或手寫 lua_pushlightuserdata + luaL_ref 管理映射。
class RefCounted {
atomic ref_{1};
public:
virtual ~RefCounted() = default;
void addRef() { ref_.fetch_add(1, memory_order_relaxed); }
void release() { if (ref_.fetch_sub(1, memory_order_acq_rel) == 1) delete this; }
int refCount() const { return ref_.load(memory_order_relaxed); }
};
template
class IntrusivePtr {
T* ptr_;
public:
IntrusivePtr(T* p = nullptr) : ptr_(p) { if (ptr_) ptr_->addRef(); }
~IntrusivePtr() { if (ptr_) ptr_->release(); }
IntrusivePtr(const IntrusivePtr& o) : ptr_(o.ptr_) { if (ptr_) ptr_->addRef(); }
IntrusivePtr& operator=(const IntrusivePtr& o) {
if (ptr_ != o.ptr_) { if (ptr_) ptr_->release(); ptr_ = o.ptr_; if (ptr_) ptr_->addRef(); }
return *this;
}
T* get() const { return ptr_; }
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
explicit operator bool() const { return ptr_; }
};
// 在 luaopen 時創建弱表
lua_newtable(L); // 表
lua_newtable(L); // 元表
lua_pushstring(L, "__mode"); lua_pushstring(L, "k"); lua_settable(L, -3); // 弱鍵
lua_setmetatable(L, -2);
lua_setfield(L, LUA_REGISTRYINDEX, "__cpp_objects"); // registry.__cpp_objects = weakTable
// 導出 C++ 對象到 Lua
void pushCppObject(lua_State* L, RefCounted* obj) {
lua_pushlightuserdata(L, obj); // 鍵
lua_pushboolean(L, 1); // 值
lua_settable(L, -3); // weakTable[obj] = true
// 設置 userdata 封裝(可選)
}
// Lua __gc 元方法(註冊到 userdata 元表)
int cppObjectGC(lua_State* L) {
RefCounted* obj = (RefCounted*)lua_touserdata(L, 1);
if (obj && obj->refCount() > 1) { // 仍有 C++ 端持有
cerr << "[LEAK DETECTED] Object " << obj << " refCount=" << obj->refCount() << " at Lua GC\n";
// 可選:強制釋放或記錄堆棧
}
return 0;
}
__gc 鉤子。IntrusivePtr 管理對象,跨 C++/Lua 傳遞時同步註冊/註銷弱表條目。collectgarbage()):遍歷弱表,檢查對象引用計數。collectgarbage("count"),檢查弱表殘留,生成洩漏報告。| 優勢 | 局限 |
|---|---|
| 零侵入業務邏輯,僅需換智能指針 | 需嵌入 Lua 運行時(~200KB) |
| 利用成熟 GC 機制,無需手寫掃描器 | 弱表鍵為 lightuserdata,無法區分對象類型 |
| 支持熱加載腳本動態調整檢測策略 | 多線程需同步 Lua 狀態訪問 |
| 可輸出 Lua 堆棧輔助定位洩漏源頭 | 循環引用需 C++ 端自行斷開(weak_ptr 輔助) |
C++ 與 Lua 結合實現內存洩漏檢測,是「腳本語言托管資源生命週期」思想的創新應用。適合嵌入式腳本化引擎、遊戲邏輯層、插件系統等已集成 Lua 的項目,以極低成本獲得運行期洩漏防護能力。