前言
如果在Lua語言中某一處死循環了!你特么的怎么去查出這特么的該死的循環到底在特么的哪里!!!
重現步驟
一打開技能界面,整個游戲就卡死不動了
開始排查
查看一下cpu占用率,unity占用60%+,應該是死循環
一開始采取冒煙式查錯法,去一些可疑的地方一個個打斷點(我們有lua調試工具可斷點)。
游戲的大循環,事件派發基層接口,lua調用c#的基層接口等等,都加了很多斷點
可喜的是~~ 完全沒有進來!
要怎么才知道當前運行哪段代碼呢?這個問題讓我想起一個東西
debug.sethook
debug庫提供了一種hook的方式,可以通過注冊一個handler函數,在lua腳本運行到某個調用時,會觸發這個handler,
獲取到相應的執行信息,並且給你一個記錄和數據維護的機會。
它主要有四種事件會觸發這個handler的調用:
- 當調用一個lua函數的時候,會觸發call事件
- 當函數返回的時候,會觸發一個return事件
- 當執行下一行代碼的時候,會觸發一個line事件
- 當運行指定數目的指令后,會觸發count事件
我們可以通過debug.sethook這個函數來注冊一個hook的handler,他有三個參數:
handler的處理函數,hook事件觸發后被調用
描述需要hook的事件類型,call、return和line事件分別對應:’c’, ‘r’, ‘l’,可以互相組合成一個字符串
獲取count事件的頻率(可選)
根據這個函數,我可以讓lua每執行一行代碼,就把它的文件名已經行號輸出到我的日志文件中
debug.sethook(
function (event, line)
WriteLogToFile(debug.getinfo(2).short_src .. ":" .. line)
end
, "l")
寫好這個工具后,我來到了技能界面前,開啟了hook!然后打開技能界面!出現吧!死循環!
我發現我的日志文件,正在以肉眼可見的速度快速增大!
打開日志后查看后,很快就找到了一段死循環邏輯!
果然,這個害我加班的BUG, 就是我的寫的!
總結
debug.sethook確實可以干很多事情,比如基於這個寫一個性能監聽工具,在函數call、return事件觸發時,計算出這個函數的執行時間。
另外這個鍋其實是我們把游戲從c#語言轉換到lua語言出現的。因為語法不一樣,c#那邊用整形除以整形得到的還是整形,但是lua會得到浮點數。