前言
如果在Lua語言中某一處死循環(huán)了!你特么的怎么去查出這特么的該死的循環(huán)到底在特么的哪里!!!

重現(xiàn)步驟
一打開技能界面,整個游戲就卡死不動了
開始排查
查看一下cpu占用率,unity占用60%+,應(yīng)該是死循環(huán)

一開始采取冒煙式查錯法,去一些可疑的地方一個個打斷點(我們有l(wèi)ua調(diào)試工具可斷點)。
游戲的大循環(huán),事件派發(fā)基層接口,lua調(diào)用c#的基層接口等等,都加了很多斷點
可喜的是~~ 完全沒有進來!

要怎么才知道當(dāng)前運行哪段代碼呢?這個問題讓我想起一個東西
debug.sethook
debug庫提供了一種hook的方式,可以通過注冊一個handler函數(shù),在lua腳本運行到某個調(diào)用時,會觸發(fā)這個handler,
獲取到相應(yīng)的執(zhí)行信息,并且給你一個記錄和數(shù)據(jù)維護的機會。
它主要有四種事件會觸發(fā)這個handler的調(diào)用:
- 當(dāng)調(diào)用一個lua函數(shù)的時候,會觸發(fā)call事件
- 當(dāng)函數(shù)返回的時候,會觸發(fā)一個return事件
- 當(dāng)執(zhí)行下一行代碼的時候,會觸發(fā)一個line事件
- 當(dāng)運行指定數(shù)目的指令后,會觸發(fā)count事件
我們可以通過debug.sethook這個函數(shù)來注冊一個hook的handler,他有三個參數(shù):
handler的處理函數(shù),hook事件觸發(fā)后被調(diào)用
描述需要hook的事件類型,call、return和line事件分別對應(yīng):’c’, ‘r’, ‘l’,可以互相組合成一個字符串
獲取count事件的頻率(可選)
根據(jù)這個函數(shù),我可以讓lua每執(zhí)行一行代碼,就把它的文件名已經(jīng)行號輸出到我的日志文件中
debug.sethook(
function (event, line)
WriteLogToFile(debug.getinfo(2).short_src .. ":" .. line)
end
, "l")
寫好這個工具后,我來到了技能界面前,開啟了hook!然后打開技能界面!出現(xiàn)吧!死循環(huán)!
我發(fā)現(xiàn)我的日志文件,正在以肉眼可見的速度快速增大!
打開日志后查看后,很快就找到了一段死循環(huán)邏輯!
果然,這個害我加班的BUG, 就是我的寫的!
總結(jié)
debug.sethook確實可以干很多事情,比如基于這個寫一個性能監(jiān)聽工具,在函數(shù)call、return事件觸發(fā)時,計算出這個函數(shù)的執(zhí)行時間。
另外這個鍋其實是我們把游戲從c#語言轉(zhuǎn)換到lua語言出現(xiàn)的。因為語法不一樣,c#那邊用整形除以整形得到的還是整形,但是lua會得到浮點數(shù)。