Unity學習-優化_卡頓緣由定位以及優化方案

除了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操做

    什麼時候會觸發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計算的開銷,可是對用戶的體驗確定沒有實時光照那麼好,通常都是出如今手遊中

陰影和烘焙的道理差很少,爲了下降實時光照的計算量,能夠將陰影設置爲假陰影,陰影在是圓的狀況,不會產生旋轉的變化,同時由於烘焙的緣由,光線沒有入射角的變化,也不會產生陰影的投射角度變化,也是在優化性能上比較經常使用的方式

相關文章
相關標籤/搜索