天天看點

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

文章目錄

  • 緩存池概念:
  • 制作方法:
  • 效果:
  • 性能測試:
    • URP添加測試
  • 結果分析:
    • 标準手機打包(中品質)
      • 緩存池
      • 無緩存池
    • 最高品質打包
      • 緩存池
      • 無緩存池

緩存池概念:

緩存池,關鍵在于緩存二字,如何緩存呢,即儲存到某個地方,每次需要創造某個物體時先從緩存池裡看看有沒有,有就從緩存池裡拿出來用,不進行創造。用完了就放到緩存池裡面、

制作方法:

我們每次建立障礙物應該先從緩存池裡面找有沒有障礙物,有的話就直接從緩存池裡面拿出來,又因為我們有很多不同的障礙物,是以我們使用字典,查找對應緩存池是否存在,沒有就建立一個,有就放進去。

緩存池字典

緩存池類:我們找一個父物體,将池子裡的東西都放到對應的池子下面

public class PoolDate
{
    public GameObject fatherObj;//緩存對象的父節點
    public List<GameObject> poolList;//對象的容器

    public PoolDate(GameObject obj, GameObject poolObj)
    {
         //給緩存池創造一個父對象,并且将其作為總pool的子物體
        fatherObj = new GameObject(obj.name);
        fatherObj.transform.parent = poolObj.transform;

        poolList = new List<GameObject>() { };
        PushObj(obj);//建立池子時将第一個物體放進去
    }

    /// <summary>
    /// 存物體
    /// </summary>
    /// <param name="obj"></param>
    public void PushObj(GameObject obj)
    {
        obj.SetActive(false);//失活,隐藏
        //存起來
        poolList.Add(obj);
        //設定父對象
        obj.transform.parent = fatherObj.transform;
    }

    /// <summary>
    /// 取物體
    /// </summary>
    /// <param name="name"></param>
    /// <param name="transform"></param>
    /// <returns></returns>
    public GameObject GetObj()
    {
        GameObject obj = null;

        obj = poolList[0];
        poolList.RemoveAt(0);

        obj.SetActive(true);
        //激活顯示
        obj.transform.parent = null;//斷開父子關系
        return obj;
    }
}

           

寫一個創造方法 替代之前的Instantiate方法

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

我們将物體名字傳進去,并且将要創造的物體和位置傳進去(如果沒有池子,就根據這個建立物體)

傳名字是為了給物體改名(一個物體第一次肯定不在池子裡,且名字會帶clone,目的就是改掉clone,友善存儲和取出)

public GameObject GetObj(string name,GameObject gameObject,Transform transform)
    { 
        //有池子,有東西
        if (poolDic.ContainsKey(name) && poolDic[name].poolList.Count > 0)
        {
            return (poolDic[name].GetObj());
        }
        else
        {
            Debug.Log("物體的名字"+name);
            Debug.Log("物體/池子不存在");
            var reNameObj = GameObject.Instantiate(gameObject, transform);//
            Debug.Log("執行個體化的物體的名字" + reNameObj.name);
            reNameObj.name = name;
            return null;
        }
        
    }
           

我們在物體出現一定時間後,不是将物體銷毀而是放到對應的池子裡。用Push方法替代Destroy方法。

在ObstacleBase腳本裡,建立Push方法,傳物體自己的名字和自己

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:
C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

在PoolManager中定義存的方法,判斷池子和其中是否有物體,存到對應名字的池子裡,并且隐藏物體。(拿出來的時候激活物體)

public void PushObj(string name, GameObject obj)
    {//裡面有池子
        if (poolObj == null)
        {
            poolObj = new GameObject("pool");
        }
        obj.SetActive(false);//失活,隐藏
        obj.transform.parent = poolObj.transform;//設定父對象
        if (poolDic.ContainsKey(name))
        {
            poolDic[name].PushObj(obj);
        }else//裡面沒有,加入一個
        {
            poolDic.Add(name, new PoolDate(obj, poolObj));
        }
    }
    
           

效果:

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:
C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

可以看到 Hierarchy視窗出現Pool,裡面是不同障礙物對應的池子,每當物體定時時間到了,就會進入緩存池,而另一邊創造物體 會優先從緩存池拿物體,當物體不夠再進行創造

最後在遊戲結束(血量清零)清除緩存池(否則重新開始遊戲可能會出現問題),每次開始遊戲也可進行緩存池的清除。

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:
C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

性能測試:

下面進行性能測試,這裡用UPR+夜神模拟器進行測評

(目前UPR已經不支援直接在編輯器模式下測試了,要麼打包測,要麼profiler)

測評方法:

下載下傳upr windows,下載下傳upr package 加載進項目裡面

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:
C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

項目打包

下載下傳夜神模拟器

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

URP添加測試

開啟模拟器同時開啟UPR windows,在urp官網登入-我的項目-建立項目-建立測試

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

這裡測試4次,兩次中品質打包,兩次最高品質打包(增加模拟器的渲染壓力),其中2次使用緩存池,2次不使用緩存池

将建立好的測試複制Session id到 Windows中,然後選擇ADB。此時模拟器應該是打開狀态且安裝了對應的app,點選之後Start,就開始測試了,測試完點選Stop即可完成測試(官網有視訊教程)

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:
C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

結果分析:

标準手機打包(中品質)

先看标準手機打包(中品質)下,緩存池對于性能的影響

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

緩存池

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:
C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:
C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

無緩存池

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:
C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:
C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

可以看到,緩存池對于性能影響不高,GC的次數居然還多了(可能是測試時間不一樣長),GC的峰值時間變長了,幀數基本變化不大,不過使用了緩存池的CPU運作比較平穩,幀數更加穩定。

最高品質打包

下面看如果渲染壓力比較高的情況下,緩存池是否會有效果:

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

緩存池

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

記憶體占用

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

GC

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

無緩存池

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

記憶體占用

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

GC

C#國中級實戰—3DFlipBird(四)緩存池與性能分析(UPR+夜神模拟器)緩存池概念:制作方法:效果:性能測試:結果分析:

可以看到,在高渲染壓力情況下,幀數直接掉一半,使用了緩存池的幀數還略低一點,記憶體情況是,使用了緩存池的記憶體确實用的更多,而且峰值GC時間和 普通畫質下的情況一樣,都 比不使用緩存池要高。還有一點情況和普通畫質一樣的是,使用了緩存池的CPU運作時間比不使用緩存池平穩運作時間更長(毛刺更少),說明幀數更穩定。

不過使用了緩存池的GC數量卻比不使用更多,這一點比較困惑,也許需要更多測試樣本。

對于此項目來說,畫質的優化是重頭,cpu優化反而不那麼重要,兩次畫質的不同直接導緻幀數掉了一半,是以如果要優化,應該往模型面數,貼圖尺寸等畫面表現來進行(粒子,shader之類的),應該看一下相關參數,不過此次重點是GC對于性能的影響,别的名額就下次再讨論了。(UPR之初體驗)

繼續閱讀