本篇不談貼圖等資源佔用內存的狀況;git
咱們項目客戶端這塊是使用了 tolua 熱更方案,基本上全部的業務邏輯都是在 lua 實現,戰鬥相關的邏輯也是同樣在 lua 實現的;github
前陣子咱們的測試同窗在 Windows 上跑遊戲測試驗收各類功能時,運 1 個小時左右,在操做系統的性能顯示代表 Unity 這個進程就佔了將近 15 個 G !致使他們必須得 kill 掉進程後從新啓動 Unity 後方可繼續運行!網絡
這很明顯的是存在內存泄漏的問題,畢竟咱們作的是手遊,內存佔用不會達到 pc 遊戲那種級別,而後我就開始着手花時間去排查!異步
後面排查出來的結果倒不是說有真正意義上的泄漏,而是由於 gc 這塊太嚴重,就是請求分配內存的速度快於 gc 的速度,到後面產生了很是多的內存碎片,當要申請一塊較大內存時老是發現當前已保留的內存(即便原本沒有用的內存總量遠大於用戶的請求)沒法知足需求,只能繼續向操做系統去申請,從而致使 Unity 佔用的總內存愈來愈大!函數
而在排查內存問題時,我所使用的工具主要是 Unity 的 Profiler 以及 github 上借鑑別人的 lua 內存泄漏工具(查 lua 內存泄漏的一個/查 lua 內存分配過快的一個 / lua 內存及 CPU 時間統計一個),具體網址就不貼了,一搜就有!工具
而後致使這個問題的緣由主要有如下幾點:性能
1.C# 中驅動 lua 的一些邏輯腳本中的函數(好比 Update 、 OnRenderImage 等等),這些接口是以模塊名拼接函數名的形式經過 tolua 調用過去的,但原來實現的人沒考慮字符串拼接會產生 gc 的問題,致使每幀在 C# 都生成了不少新的字符串對象,從而致使了 mono gc,大概是每幀 3~4KB;測試
2.後處理特效腳本形成了不少的 mono gc ,大概是每幀6KB,由於咱們的 MainCamera 上掛了 四、5 個處理後效的腳本優化
3.lua 中一些業務邏輯的計算使用了客戶端的實時時間,這個是從 C# 那邊經過 userdata 給過來的,但由於如今 tolua 是經過字符串的形式支持了 64 位整型值,每次使用的時候都會進行 tonumber(tostring(realTime)) 轉換操做,從而致使了一旦調用頻繁(好比在 Update 中調用),就會產生不少的 lua string(也是 gc 對象)this
4.lua 中的戰鬥邏輯大量的向量計算(好比位置/方向/旋轉),舉個例子:
1 local function _init() 2 this.curPos = Vector3.New(0, 0, 0), 3 this.moveDirN = Vector3.New(1, 0, 0) 4 end 5 6 --... 7 8 local function _update() 10 local nextPos = this.curPos + this.moveDirN * 3 11 --... 12 end
這時在 _update 中計算 nextPos 的時候,每幀就會多產生兩個 Vector3 table 出來——由於 tolua 在 lua 中封裝了 Vector3 這個類(主要做用應該是避免頻繁地和 C# 進行交互,就是多花了一點內存,節省下客觀的 cpu 執行時間),重載數學運算符的實現,一次計算+-*/運算就會多一個 new Vector3,不過這也是合理的,原本實現上就該是這樣,否則用戶會產生疑惑的!
5.在事件(好比進入場景事件/主角升級事件等等)分發這塊,原來的人使用了一個開源的事件庫,其中用了 lua 協程來處理事件派發:每派發一個事件給不一樣監聽者,都會建立單獨的協程去處理,但處於戰鬥過程當中,會有各類各樣不一樣但事件須要派發,也就是說這個量仍是挺大但,具體 gc 數值大概是每幀 1KB ,但按咱們項目現有狀況來講,派發事件這一操做沒有異步的需求,都是須要全部監聽者直接執行便可,也沒有說某個事件的處理時間已經達到了不能容忍的程度,因此暫時是沒有異步這一個需求,後續若是有再把協程加回來,而且封裝多一層,也就是進行協程複用,不會頻繁產生新的協程;
6.其餘的也是跟上述第 4 點有類似之處,都是在調用頻率很是頻繁的函數不斷的新建立 lua table,這塊的量大概是有 8KB;
7.這一點我尚未細測,但猜想是有可能的,就是網絡消息的收發這塊,有些很頻繁的消息,好比移動、技能等等,每次都是一個的 new,後續這塊也多是一個熱點;
8.同 7 同樣,處理視野範圍內的全部實體的移動、技能的這些邏輯也有可能會致使比較多的 lua gc,後面再確認看看;
確認了上述幾個大頭緣由以後,就用了相應的優化方案進行優化,這個就不細說了,由於緣由都確認了,那麼方案基本就是確認的:思路就是一個,怎麼避免或者說最大程度減小 gc!現階段咱們遊戲在 pc 上的內存佔用基本是比較穩定的,持續戰鬥兩個小時,多分配出來的內存佔用基本在幾十 M 這個級別,後續再在手機上進行進一步的確認測試!
寫在最後:打開 Unity Profiler 在運行過程當中,其自己也是佔用 mono 內存的,因此這塊得注意,別被誤導了,好比說在 Memory Profiler 中會它自身產生的 gc 曲線,這塊經過開關就能夠開啓/關閉它在 CPU Profiler 中的顯示!
2020-08-21
本篇完,轉載請註明出處——楓葉未紅