溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

lua內(nèi)存泄漏檢測工具原理及設(shè)計是怎么的

發(fā)布時間:2021-12-03 16:19:33 來源:億速云 閱讀:305 作者:柒染 欄目:大數(shù)據(jù)

這篇文章將為大家詳細(xì)講解有關(guān)lua內(nèi)存泄漏檢測工具原理及設(shè)計是怎么的,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

Google一下“l(fā)ua內(nèi)存泄漏檢測”,基本都是直接或間接指向云風(fēng)多年前寫的《一個 Lua 內(nèi)存泄露檢查工具》,其思路是給虛擬機做個快照,記錄下所有g(shù)c對象地址及引用關(guān)系,然后通過對比兩次快照來分析內(nèi)存泄漏情況。文章似乎把內(nèi)存泄漏等同于某個gc對象的新增了。

然而,新增gc對象就代表內(nèi)存泄漏?看下這段代碼:

local no_leak = {}function innocent()
    no_leak.a = {x = 1}
    no_leak.b = {y = 1}end

innocent函數(shù)每次執(zhí)行都會新增兩個table并持有它們,但這明顯不是內(nèi)存泄漏,而且這是很常見的寫法。

不新增gc對象就代表沒內(nèi)存泄漏?也不是:

local local_leak = {}function make_leak()
    table.insert(local_leak, 1)end

這種泄漏文章提供的工具貌似就無能為力。它只記錄gc對象及gc對象間的引用關(guān)系。但數(shù)字不是gc對象。

帶GC語言的內(nèi)存泄漏

C/C++這類語言的內(nèi)存泄漏,是分配了內(nèi)存忘了釋放,但GC會幫我們自動釋放這類內(nèi)存。而在帶GC的語言的內(nèi)存泄漏,則是往一個容器里頭塞東西忘了刪掉。

往一個容器里頭塞東西忘了刪掉會導(dǎo)致什么現(xiàn)象?

當(dāng)然是導(dǎo)致這容器變大,所以疑似內(nèi)存泄漏檢測就變成了容器大?。ㄊ欠襁f增)檢測。

這在lua里頭又特別簡單,因為。。lua只有一種容器--table。

lua內(nèi)存泄漏檢查

核心代碼十分簡單,只有十來行C代碼:

typedef void (*TableSizeReport) (const void *p, int size);LUA_API void xlua_report_table_size(lua_State *L, TableSizeReport cb, int fast){GCObject *p = G(L)->allgc;while (p != NULL){if (p->tt == LUA_TTABLE){Table *h = gco2t(p);cb(h, table_size(h, fast));}p = p->next;}}

遍歷所有對象,如果是table,則把指針和size報告給調(diào)用者。

這個C代碼將由C#調(diào)用,并記錄下table的size信息,也灰常簡單:

static Data getSizeReport(LuaEnv env){
    Data data = new Data();
    data.Memroy = env.Memroy;

    LuaDLL.Lua.xlua_report_table_size(env.L, (IntPtr p, int size) => {
        data.TableSizes.Add(p, size);
    }, 0);

    return data;}

好了,接下來對比前后size信息,就可以找出可能存在內(nèi)存泄漏的table的指針了,這里就不貼代碼了,文章中所有代碼都可以在xLua開源項目中找到。

table詳細(xì)信息

光拿table的指針是沒啥用的,我們要得到更多信息才定位。

一般而言,table順其引用鏈往上找,都能歸結(jié)到三個地方:

1、upvalue,比如你在lua腳本定義的local xx = {};

2、全局變量;

3、c側(cè)共用的一個特殊table:registry;

當(dāng)然,棧也可能引用table,但我們是在C#調(diào)用C代碼,當(dāng)時沒跑lua,棧應(yīng)該是空的,而且僅僅棧指向的對象,我們可以先不管,這對象要么是臨時的,要么后面還是被上面三個地方引用。

table詳細(xì)信息思路

1、獲取對象引用關(guān)系,生成反向索引表;

2、從反向索引表查找到疑似泄漏table,然后根據(jù)反向索引往上找,一直找到上述的三個根,生成路徑

一個典型泄漏信息報告是這樣的:

total memroy: 87
potential leak(180) in {leak2.lua:local anthor_leak.a[1].b,_R.ref_anthor_leak.a[1].b}potential leak(181) in {_G.global_leak}potential leak(180) in {leak1.lua:local local_leak}

第一個行表示有個大小為180的疑似泄漏table,它被兩個地方引用了

一個是leak2.lua文件的局部變量anthor_leak,位于這個局部變量的a[1].b子節(jié)點

一個是registry表(上面的第三個地方),ref_anthor_leak.a[1].b子節(jié)點

快泄漏和慢泄漏

如果程序中存在一個泄漏很快以及一個泄漏很慢的地方,我們兩次對比table size信息,很可慢的因為沒漲而被無視。

這也沒關(guān)系,當(dāng)你找到泄漏快的地方,解決了快的,慢的就能被檢查出來了。

測試?yán)右舱故具@這種情況。

關(guān)于lua內(nèi)存泄漏檢測工具原理及設(shè)計是怎么的就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

lua
AI