1. 程式人生 > >手遊客戶端的效能篇(一)----Unity和C#版之Foreach GC

手遊客戶端的效能篇(一)----Unity和C#版之Foreach GC

          序:昨天去了南京的湯山紫清湖溫泉,安利一下,價格也不貴(不是打廣告。。。不貼怎麼訂票之類的,有興趣可以評論),還去見了多年未見的老友啊~不出意外的話下篇是手遊客戶端的效能篇(二)----Unity和C#版,想寫優化和效能想寫很久了,正好藉機會總結一下。

          先放一下2018年TX移動遊戲技術評審標準:(摘自騰訊遊戲學院)

      1.foreach的GC問題(我在Unity 5.3.2.f1上測試還是有的)

       eg:以下這幾種使用方法都是有GC的(例子裡定義了Vehicle類,它代表著所有的自定義和非自定義型別):

            foreach(Vehicle car in vehicleList)

             {

             }

            foreach(KeyValuePair<int, Vehicle>  pair in vehicleDic)

            {

            }

            foreach(Vehicle car in vehicleDic.Values)  

             {

             }

      總結:使用Foreach對陣列不會有GC,但是Foreach對Dic和List都有GC。

      再看看下面這種情況:

       (一)
        IEnumerator iter = vehicleDic.GetEnumerator();
        while (iter.MoveNext())
        {

        }
       (二)
        var varIter = vehicleDic.GetEnumerator();
        while (varIter.MoveNext())
        {

        }

     (三)

       using (var varIter = peopleDictionary.GetEnumerator())
        {
            while (varIter.MoveNext())
            {

            }
        }

 用profile檢視後我們驚奇的發現(一)(三)的仍然有GC,(二)沒有GC。

為什麼呢???

 使用ILSPY反編譯可以看待IL程式碼,下面揭開謎底:

反編譯-〉C#:

編譯前:

foreach(KeyValuePair<int, Vehicle>  pair in vehicleDic)

 {

 }

編譯後:

using (Dictionary<int, Vehicle>.Enumerator   iter= this.vehicleDic.GetEnumerator())

{

     while (iter.MoveNext())

      {

      }

}

再對比一下while沒有GC的情況:

 var varIter = vehicleDic.GetEnumerator();
 while (varIter.MoveNext())
  {

  }

對比,是不是說沒有用var就沒有GC呢?其實不然,因為你會發現兩種情況基本沒有區別,區別只在於使用using後會立即呼叫GC,而後面這種等系統來呼叫。所以只是看上去!只是看上去最後這種沒有GC。

產生GC的真正原因:

GetEnumerator()返回的是值型別,而在中間層程式碼會轉換為引用型別,造成裝箱(後面文章會介紹裝箱和拆箱),導致GC。到所以我們應該怎麼寫?

       var varIter = vehicleDic.GetEnumerator();
       while (varIter.MoveNext())
       {

       }

正確寫法如上,雖然也會產生GC,但是不會立即呼叫,會等到系統觸發呼叫,也就不容易造成卡幀。

(真正理解這些點,才可以更好的優化效能,提高效能,下篇再見!大家有喜歡的點個贊,寫個評論,歡迎拍磚,歡迎一起探討。套用抖音上的話,你們給已經有那麼多粉絲的人點贊沒有用的!給我點,我會把你們的文章都看一遍!把你們的評論都認真回覆一遍!hhh)