對於目前絕大多數基於Unity引擎開發的專案而言,其託管堆記憶體是由Mono分配和管理的。“託管” 的本意是Mono可以自動地改變堆的大小來適應你所需要的記憶體,並且適時地呼叫垃圾回收(Garbage Collection)操作來釋放已經不需要的記憶體,從而降低開發人員在程式碼記憶體管理方面的門檻。
但是這並不意味著研發團隊可以在程式碼中肆無忌憚地開闢託管堆記憶體,因為目前Unity所使用的Mono版本存在一個很嚴重的問題,即:Mono的堆記憶體一旦分配,就不會返還給系統。這意味著Mono的堆記憶體是隻升不降的。舉個例子,專案執行時,在場景A中開闢了60MB的託管堆記憶體,而到下一場景B時,只需要使用20MB的託管堆記憶體,那麼Mono中將會存在40MB空閒的堆記憶體,且不會返還給系統。這是我們非常不願意看到的現象,因為對於遊戲(特別是移動遊戲)來說,記憶體的佔用可謂是寸土寸金的,讓Mono毫無必要地鎖住大量的記憶體,是一件非常浪費的事情。
常見的不必要的堆記憶體分配:
- 高頻率地 New Class/Container/Array等。切記不要在Update、FixedUpdate或較高呼叫頻率的函式中開闢堆記憶體,這會對你的專案記憶體和效能均造成非常大的傷害。做個簡單的計算,假設你的專案中某一函式每一幀只分配100B的堆記憶體,幀率是1秒30幀,那麼1秒鐘遊戲的堆記憶體分配則是3KB,1分鐘的堆記憶體分配就是180KB,10分鐘後就已經分配了1.8MB。如果你有10個這樣的函式,那麼10分鐘後,堆記憶體的分配就是18MB,這期間,它可能會造成Mono的堆記憶體峰值升高,同時又可能引起了多次GC的呼叫。
- Log輸出,研發團隊應對自身Log的輸出進行嚴格的控制,僅保留關鍵Log,以避免不必要的堆記憶體分配。
- String連線
- GetComponent