除了Unity的一些組件優化技巧以外,更多的細節處於代碼層面上算法
最近學習優化,看到一篇文章,寫的很詳細,從底層原理到咱們windows
的實際處理,都有一些很是好的建議,能夠推薦給小夥伴們看看緩存
https://www.jianshu.com/p/289de89a6609性能優化
===========如何定位程序的哪個環節產生了過大的開銷============ide
使用Uinty的Profiler工具,能夠比較精準快速的定位程序的哪個位置產生了大開銷工具
首先在build setting裏面勾選Autoconnect Profiler性能
而後在windows欄選擇proflier便可學習
打開以後便可監控遊戲每一幀的運行狀態了,能夠根據FPS和每一幀運行的時間判斷遊戲的卡頓程度優化
肯定某一幀的佔用率太高以後ui
點擊波狀圖,就會暫停遊戲
下方就會列出當前遊戲運行的消耗詳細信息了
跟進total欄的百分比,便可定位是哪一個位置產生了最大的消耗,從而進行相應優化了
這個工具是用來定位優化點的,具體的優化方案能夠參考下面的優化方式
因爲篇幅有限,並且這個工具應該大部分人都知道並且會用,就不過多贅述了。
不明白的能夠參閱這篇做者的 https://www.jianshu.com/p/a7cee5e548cf
寫的很是詳細
==================代碼層優化====================
1、內存管理
1:GC原理
C#的垃圾回收是自動託管的,垃圾回收系統也有一套生命週期和統計流程,下面就是關於GC的總體流程:
1)一次GC的過程分爲2個階段:
標記清除階段,GC會假設堆中全部對象均可以被回收,而後找出不能回收的對象,打上清除標記,剩下的就是要被回收的了。找的過程就是檢查對象 有沒有被其餘的對象引用的過程,若是這個對象在程序中沒有被引用到,那麼就會被打上清除的標記。
從新地址排列階段,標記清除的對象被清除以後,堆裏面的空間就會變成不是連續的了,GC的第二部就會開始從新排列還存在的對象,使堆中的地址 分配變成連續的。
2)整個.net的GC流程:
在進行.Net的GC階段,是不止一次GC操做的,C#採用了分代算法,先對程序裏面的內存進行分代管理,再根據不一樣的代,進行不一樣力度的清理。
這裏面的生命週期爲3代, 第0代是新建立的代碼,在達到了0代集合的閾值以後,觸發0代的GC,倖存的對象會進入1代集合, 同理,在1代集合達到了閾值 的時候,也會進行GC,可是此次GC是 0代和1代一塊兒執行,以此類推,2代集合GC的時候也會進行1代 2代的CG操做。按消耗量的比例應該是 1:10:100
這種分代算法是基於 老的對象生命週期通常都比新的對象生命週期長,就像公司的員工同樣,時間較長的員工公司看來通常都比新進來的員工穩定性要大。
2:優化策略
明白了大體GC的流程以後會發現,GC會消耗大量的CPU性能,由於這裏面會經歷不少次的運算以及遍歷等
接下來是弄清楚GC何時被觸發,以及如何規避影響用戶體驗的GC操做
1:跟進分代算法,在容量達到閾值的時候會發生,
2:GC會不時的自動運行(頻率因平臺而異)。
3:手動強制調用GC
大體的優化思路就是 下降每一次GC的運行時間(減小垃圾對象,使GC的過程當中儘可能少的遍歷),下降GC的頻率(下降觸發GC機制的次數),在加載地圖等須要用戶等待的遊戲流程裏面主動GC。
接下來就是跟進3種觸發機制作咱們代碼上的優化了
1)、儘可能少new沒必要要的字段
1 object obj = null; 2 update() 3 { 4 object = somebody; 5 } 6 7 update() 8 { 9 object obj =somebody; 10 }
上面的賦值方式只會在開闢一個內存空間,第二種會反覆開闢內存空間,這些空間通常在一代GC裏面就會被釋放掉。屬於最無用的代碼方式(不必的 狀況下)。
2).使用對象池
對象池的使用會大大下降新內存空間的使用,他會在一個內存空間反覆給新的值。
3).儘可能使用緩存機制,少使用Instantiate實例化新對象,由於這裏Unity會初始化他身上的組件以及各類序列化的操做,各個物體會根據自身的組件,建立耗時都 不相同
4).字符串的操做
string的拼接操做是在內部從新new 一個新的出來,由於string在C#是不可變動到,因此在每一次的+= 就至關於new了一個新的字符串出來,若是出現比較頻繁 的拼接操做,stringBuilder會比string 更好,可是string在對字符串的操做上會比stringBuider好,至於使用哪種就看具體的需求了。
5).在地圖加載等須要等待的過程當中主動進行GC。
避免內存消耗還有不少的方式,我也是剛剛開始比較全面的學習性能優化,在以上也是我在網上搜集了一些本身能理解的處理方式。
CPU性能管理:
1、代碼層:
一、 儘可能避免空的Update(),只要寫了Update(),無論是否是空的,Unity都會去執行,這裏會增長開銷
二、Find getcomponent 等查找的方法,Unity都會去遍歷場景對象和組件,在大型項目中,場景對象一旦變多就會產生很大的開銷了,儘可能在start裏面調用而不 是update裏面反覆使用
三、Update裏面儘可能少作遍歷,一次UpDate 就會遍歷一次,這是一個很大的開銷了。
四、在業務需求不影響的狀況下,可讓Update裏面的邏輯使用計時器,增長間隔,1秒調用一次,2秒調用一次等。
五、在能夠知道觸發條件的狀況下,儘可能使用委託的方式處理觸發效果,而不是一次次的遍歷目標的觸發狀態
六、和上面同樣,儘可能在設計代碼的時候,使用觀察者模式,理論上來講,遊戲的大部分邏輯均可以使用觸發後再執行,特別是UI。(在使用lua熱更新的項目 中,大部分的遊戲邏輯流程都是經過事件消息的觸發來完成的,由於裏面沒有Uinty那麼專業的生命週期)
七、for 和 foreach 的取捨 :
在固定長度或長度不須要計算的時候for循環效率高於foreach.
在不肯定長度,或計算長度有性能損耗的時候,用foreach比較方便
2、渲染層:
渲染層的優化包括 圖集的結構設計、模型的處理、LOD、mipMap、烘焙等、陰影處理
圖集的結構設計是爲了減小額外的draw call,儘可能以模塊劃分,由於原則上每一個模塊之間的UI元素是不會互相耦合的。Unity的texture的大小是根據2的冪來計算到。若是你的圖片真實大小是1025,那麼他會建立一塊2048的texture,也是浪費開銷的行爲。
模型的處理要結合LOD的使用,在固定視角、固定攝像機深度的遊戲中,LOD的發揮效果不是很大,更多的是製做模型的時候就肯定了模型精度
LOD和MipMap的使用會帶來很大的性能提高,可是會受項目影響,具體看項目而定
烘焙就是在遊戲發佈以前,場景融合光照提早產生新的貼圖,使這個場景不用進行動態光照計算 就能夠達到光照的效果,下降了CPU計算的開銷,可是對用戶的體驗確定沒有實時光照那麼好,通常都是出如今手遊中
陰影和烘焙的道理差很少,爲了下降實時光照的計算量,能夠將陰影設置爲假陰影,陰影在是圓的狀況,不會產生旋轉的變化,同時由於烘焙的緣由,光線沒有入射角的變化,也不會產生陰影的投射角度變化,也是在優化性能上比較經常使用的方式