您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(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é)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(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)容。