• unity之性能优化 对象池之【类对象池】


    对象池老生常谈的问题了,对象池即对象的池子。大概描述下:对象池内寄放着废弃的对象,当程序需要某对象去池子里拿,让废弃对象再利用,如果没有则创建;用完之后再将废弃的对象回收。一句话:让内存重复利用的优化方案。

    解决痛点:

    1.省去很多内存碎片得问题;

    2.节省实例对CPU的消耗;

    3.触发垃圾回收(GC)的次数少了。

    注意事项:

    在场景切换的时候,要销毁整个对象池,避免无意义内存驻留。

    废话说完了,先上图:

     思路是这样的:

    按C键进行取池(去池子里面拿),按D键进行回池(对象回收),常驻数量:设置池中对象数量保持多少不进行释放,没有设置则进行释放。这里设置的是3秒自动释放池中对象。

     

    代码如下:

    类对象池:

      1 using System;
      2 using System.Collections.Generic;
      3 
      4 /// <summary>
      5 /// 类对象池
      6 /// </summary>
      7 public class TestClassObjectPool : IDisposable
      8 {
      9     /// <summary>
     10     /// key 类型哈希码
     11     /// </summary>
     12     private readonly Dictionary<int, Queue<object>> m_Pools;
     13 
     14     /// <summary>
     15     /// 常驻
     16     /// </summary>
     17     public readonly Dictionary<int, byte> ResidentDic;
     18 
     19 
     20 #if UNITY_EDITOR
     21     /// <summary>
     22     /// 编辑器面板监控用的
     23     /// </summary>
     24     public readonly Dictionary<Type, int> InspectorDic;
     25 #endif
     26 
     27 
     28     public TestClassObjectPool()
     29     {
     30         m_Pools = new Dictionary<int, Queue<object>>();
     31         ResidentDic = new Dictionary<int, byte>();
     32 #if UNITY_EDITOR
     33         InspectorDic = new Dictionary<Type, int>();
     34 #endif
     35     }
     36 
     37     /// <summary>
     38     /// 取池
     39     /// </summary>
     40     internal T Dequeue<T>() where T : class, new()
     41     {
     42         lock (m_Pools)
     43         {
     44             int key = typeof(T).GetHashCode();
     45             m_Pools.TryGetValue(key, out Queue<object> queueList);
     46             if (queueList == null)
     47             {
     48                 queueList = new Queue<object>();
     49                 m_Pools[key] = queueList;
     50             }
     51             else
     52             {
     53                 if (queueList.Count > 0)
     54                 {
     55                     UnityEngine.Debug.LogError("池中存在对象 取出一个");
     56 #if UNITY_EDITOR
     57                     InspectorDic.TryGetValue(typeof(T), out int count);
     58                     count = count > 0 ? --count : 0;
     59                     InspectorDic[typeof(T)] = count;
     60 #endif
     61                     return (T)queueList.Dequeue();
     62                 }
     63             }
     64             UnityEngine.Debug.LogError("对象不存在 进行创建");
     65             return new T();
     66         }
     67     }
     68 
     69     /// <summary>
     70     /// 回池
     71     /// </summary>
     72     internal void Equeue(object obj)
     73     {
     74         lock (m_Pools)
     75         {
     76             int key = obj.GetType().GetHashCode();
     77             m_Pools.TryGetValue(key, out Queue<object> queueList);
     78             if (queueList != null)
     79             {
     80                 queueList.Enqueue(obj);
     81 #if UNITY_EDITOR
     82                 InspectorDic.TryGetValue(obj.GetType(), out int count);
     83                 count++;
     84                 InspectorDic[obj.GetType()] = count;
     85 #endif
     86                 UnityEngine.Debug.LogError("对象回池了");
     87             }
     88         }
     89     }
     90 
     91     /// <summary>
     92     /// 常驻
     93     /// </summary>
     94     /// <typeparam name="T"></typeparam>
     95     /// <param name="count"></param>
     96     internal void SetResident<T>(byte count) where T : class
     97     {
     98         lock (m_Pools)
     99         {
    100             int key = typeof(T).GetHashCode();
    101             if (!ResidentDic.ContainsKey(key))
    102             {
    103                 ResidentDic[key] = count;
    104             }
    105         }
    106     }
    107 
    108     internal void ClearPool()
    109     {
    110         var vr = m_Pools.GetEnumerator();
    111         while (vr.MoveNext())
    112         {
    113             ResidentDic.TryGetValue(vr.Current.Key, out byte count);
    114             Queue<object> queue = vr.Current.Value;
    115             if (queue.Count > count)
    116             {
    117                 object obj = queue.Dequeue();
    118 #if UNITY_EDITOR
    119                 InspectorDic.TryGetValue(obj.GetType(), out int insCount);
    120                 insCount--;
    121                 InspectorDic[obj.GetType()] = insCount;
    122                 if (queue.Count == 0)
    123                 {
    124                     InspectorDic.Remove(obj.GetType());
    125                 }
    126 #endif                          
    127             }
    128         }
    129     }
    130 
    131     public void Dispose()
    132     {
    133         m_Pools.Clear();
    134     }
    135 
    136 }

    对象池管理器:

     1 using System;
     2 using UnityEngine;
     3 
     4 /// <summary>
     5 /// 对象池管理器
     6 /// </summary>
     7 public class TestPoolManager : IDisposable
     8 {
     9     /// <summary>
    10     /// 下次运行时间 
    11     /// </summary>
    12     private float m_NextRunTime = 0;
    13 
    14     /// <summary>
    15     /// 释放间隔
    16     /// </summary>
    17     private float ClearInterval = 3;
    18 
    19     public TestClassObjectPool ClassPool { get; private set; }
    20     public TestPoolManager()
    21     {
    22         ClassPool = new TestClassObjectPool();
    23         m_NextRunTime = Time.time;
    24     }
    25 
    26     internal void Init()
    27     {
    28     }
    29 
    30     public void OnUpdate()
    31     {
    32         if (Time.time > m_NextRunTime + ClearInterval)
    33         {
    34             m_NextRunTime = Time.time;
    35             ClassPool.ClearPool();
    36         }
    37     }
    38 
    39     public void Dispose()
    40     {
    41         ClassPool.Dispose();
    42     }
    43 }

     

    游戏入口:

     1 using UnityEngine;
     2 
     3 public class TestGameEntry : MonoBehaviour
     4 {
     5     public static TestGameEntry Instance;
     6     public static TestTimeManager TimeMgr { get; private set; }
     7     public static TestPoolManager PoolMgr { get; private set; }
     8 
     9     private void Awake()
    10     {
    11         Instance = this;
    12     }
    13 
    14     void Start()
    15     {
    16         InitManagers();
    17         Init();
    18     }
    19 
    20     void InitManagers()
    21     {
    22         TimeMgr = new TestTimeManager();
    23         PoolMgr = new TestPoolManager();
    24     }
    25 
    26     void Init()
    27     {
    28         TimeMgr.Init();
    29         PoolMgr.Init();
    30     }
    31 
    32     void Update()
    33     {
    34         TimeMgr.OnUpdate();
    35         PoolMgr.OnUpdate();
    36     }
    37 
    38     private void OnDestroy()
    39     {
    40         TimeMgr.Dispose();
    41         PoolMgr.Dispose();
    42     }
    43 }

     

    编辑器拓展:

     1 using UnityEditor;
     2 using UnityEngine;
     3 
     4 [CustomEditor(typeof(TestGameEntry))]
     5 public class TestPoolManagerInspector : Editor
     6 {
     7     public override void OnInspectorGUI()
     8     {
     9         base.OnInspectorGUI();
    10         serializedObject.Update();//实时刷新
    11         GUILayout.Space(10);
    12         GUILayout.BeginVertical("box");
    13         GUILayout.BeginHorizontal("box");
    14         GUILayout.Space(20);
    15         GUILayout.Label("类对象");
    16         GUILayout.Label("池中数量");
    17         GUILayout.Label("常驻数量");
    18         GUILayout.EndHorizontal();
    19         if (TestGameEntry.PoolMgr != null)
    20         {
    21             var insEnumerator = TestGameEntry.PoolMgr.ClassPool.InspectorDic.GetEnumerator();
    22             while (insEnumerator.MoveNext())
    23             {
    24                 GUILayout.BeginHorizontal("box");
    25                 GUILayout.Label(insEnumerator.Current.Key.Name, GUILayout.Width(100));
    26                 GUILayout.Label(insEnumerator.Current.Value.ToString(), GUILayout.Width(60));
    27                 TestGameEntry.PoolMgr.ClassPool.ResidentDic.TryGetValue(insEnumerator.Current.Key.GetHashCode(), out byte residentCount);
    28                 GUILayout.Label(residentCount.ToString(), GUILayout.Width(80));
    29                 GUILayout.EndHorizontal();
    30             }
    31         }
    32         GUILayout.EndVertical();
    33         serializedObject.Update();
    34         Repaint();//重绘
    35     }
    36 }

     

    测试用例:

     1 using UnityEngine;
     2 
     3 public class userData
     4 {
     5 }
     6 
     7 public class userData11
     8 {
     9 }
    10 
    11 public class TestPool_2 : MonoBehaviour
    12 {
    13     System.Text.StringBuilder sb = null;
    14     userData aa = null;
    15     userData11 aa11 = null;
    16 
    17     private void Update()
    18     {
    19         if (Input.GetKeyDown(KeyCode.C))
    20         {
    21             Debug.Log("按了C键 --------");
    22             sb = TestGameEntry.PoolMgr.ClassPool.Dequeue<System.Text.StringBuilder>();  //new System.Text.StringBuilder();            
    23             TestGameEntry.PoolMgr.ClassPool.SetResident<System.Text.StringBuilder>(2);
    24             sb.Length = 0;
    25             sb.Append("111");
    26             Debug.Log(sb.ToString());
    27 
    28             aa = TestGameEntry.PoolMgr.ClassPool.Dequeue<userData>();
    29             TestGameEntry.PoolMgr.ClassPool.SetResident<userData>(1);
    30             aa11 = TestGameEntry.PoolMgr.ClassPool.Dequeue<userData11>();
    31         }
    32 
    33         if (Input.GetKeyDown(KeyCode.D))
    34         {
    35             if (sb == null) return;
    36             Debug.Log("按了D键 ========== ");
    37             TestGameEntry.PoolMgr.ClassPool.Equeue(sb);
    38             TestGameEntry.PoolMgr.ClassPool.Equeue(aa);
    39             TestGameEntry.PoolMgr.ClassPool.Equeue(aa11);
    40         }
    41     }
    42 }

     

    欢迎大家提出批评建议和指教哈~

     

  • 相关阅读:
    【转】Windows Server 2012无法安装 .NET3.5-安装角色或功能失败,找不到源文件-十有三博客
    jfinal undertow项目集成JDK做成系统服务
    【转】解决undertow多个https证书的web项目部署问题
    说说 C# 9 新特性的实际运用
    php RSA加解密
    mscomm控件使用详解 转
    VB中让listview自动调整列宽
    QueryPerformanceFrequency使用方法--Windows高精度定时计数
    VB6鼠标滚轮插件
    Microsoft Visual C++ 6.0快捷键(绝对值得掌握)
  • 原文地址:https://www.cnblogs.com/zhaolaosan/p/15313521.html
Copyright © 2020-2023  润新知