• Unity Xlua热更新框架(八):对象池


    13. 对象池

    13-1. 对象池

    • 作用:减少对象创建和销毁的次数,让对象可以重复使用
    • 对象特点:使用频率高、使用次数多
    • 对象类型:AssetBundle需要Unload、GameObject(UI、Entity、Sound)需要Destroy

    传统对象池:

    • 原理:先创建一定数量的对象、使用时从池子取,用完了还回去
    • 特点:相同对象、多次使用

    我们的对象池:

    • 特点:对象可以是多种类型、短时间内可重复使用、过期自动销毁
    • 设计原理:池内不创建对象,对象在外部创建,使用完放入对象池,再次使用从对象池取

    创建Framework/ObjectPool/PoolObject

    using UnityEngine;
    
    //专门用来存放ObjectPool里放置的不同对象的数据类
    public class PoolObject
    {
        //具体对象
        public Object Object;
        
        //对象名字
        public string Name;
        
        //最后一次使用时间,,,针对不同类型的对象有不同的有效时长,超过有效时长就销毁
        public System.DateTime LastUseTime;
    
        //生成实例,放入池子时,会记录一下上一次的使用时间
        public PoolObject(string name, Object obj)
        {
            Name = name;
            Object = obj;
            LastUseTime = System.DateTime.Now;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    对于AssetBundle和GameObject的存和取都不相同。AssetBundle不需要设置非激活。
    创建Framework/ObjectPool/PoolBase

    using System.Collections.Generic;
    using UnityEngine;
    
    public class PoolBase : MonoBehaviour
    {
        //自动释放时间/s
        protected float m_ReleaseTime;
        
        //上次释放资源的时间/毫微妙 1(秒) = 10000000(毫微秒)
        protected long m_LastReleaseTime = 0;
        
        //真正的对象池
        protected List<PoolObject> m_Objects;
    
        public void Start()
        {
            m_LastReleaseTime = System.DateTime.Now.Ticks;
        }
        
        //初始化对象池
        public void Init(float time)
        {
            m_ReleaseTime = time;
            m_Objects = new List<PoolObject>();
        }
    
        //取出对象
        public virtual Object Spawn(string name)
        {
            foreach (PoolObject po in m_Objects)
            {
                if (po.Name == name)
                {
                    //放在池子里的一定是还没有用到的,用到的就拿出来
                    m_Objects.Remove(po);
                    return po.Object;
                }
            }
            return null;
        }
        
        //回收对象
        public virtual void UnSpawn(string name, Object obj)
        {
            PoolObject po = new PoolObject(name, obj);
            m_Objects.Add(po);
        }
        
        //释放,父类什么都不做
        public virtual void Release()
        {
            
        }
    
        private void Update()
        {
    		//父类需要按给定时间执行一次Release,但是到底释放没有,需要根据继承父类的子类来确定,其内部的时间是否到了销毁时间
            if (System.DateTime.Now.Ticks - m_LastReleaseTime >= m_ReleaseTime * 10000000)
            {
                //刷新时间
                m_LastReleaseTime = System.DateTime.Now.Ticks;
                Release();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    public class GameObjectPool : PoolBase
    {
        //去物体:在池子中查找,如果有物体就激活,没有返回null
        public override Object Spawn(string name)
        {
            Object obj = base.Spawn(name);
            if (obj == null)
                return null;
            
            GameObject go = obj as GameObject;
            go.SetActive(true);
            return obj;
        }
    
        //存物体:把物体设置非激活,然后放进池子回收
        public override void UnSpawn(string name, Object obj)
        {
            GameObject go = obj as GameObject;
            go.SetActive(false);
            go.transform.SetParent(this.transform, false);
            base.UnSpawn(name, obj);
        }
    
        public override void Release()
        {
            base.Release();
            foreach (PoolObject item in m_Objects)
            {
                if (System.DateTime.Now.Ticks - item.LastUseTime.Ticks >= m_ReleaseTime * 10000000)
                {
                    Debug.Log("GameObjectPool release time:" + System.DateTime.Now);
                    Destroy(item.Object);
                    m_Objects.Remove(item);
                    //因为删除了list一项之后,不能用迭代器了,需要递归一下跳出
                    Release();
                    return;
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    public class AssetPool : PoolBase
    {
        public override UnityEngine.Object Spawn(string name)
        {
            return base.Spawn(name);
        }
    
        public override void UnSpawn(string name, UnityEngine.Object obj)
        {
            base.UnSpawn(name, obj);
        }
    
        public override void Release()
        {
            base.Release();
            foreach (PoolObject item in m_Objects)
            {
                if (System.DateTime.Now.Ticks - item.LastUseTime.Ticks >= m_ReleaseTime * 10000000)
                {
                    Debug.Log("AssetPool release time:" + System.DateTime.Now);
                    Manager.Resource.UnloadBundle(name);
                    m_Objects.Remove(item);
                    Release();
                    return;
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    public void UnloadBundle(string name)
    {
        
    }
    
    • 1
    • 2
    • 3
    • 4

    创建Framework-Manager-PoolManager

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    //运行时,在pool下创建一个poolName的子物体,挂载脚本,AssetBundle挂载AssetPool,GameObject挂载GameObjectPool脚本
    //挂载的脚本就是对象池,先Init初始化对象池,然后将这个对象池添加到PoolManager中进行管理。
    //通过PoolManager的m_Pools管理里面的对象池,分别取出和放回对象
    public class PoolManager : MonoBehaviour
    {
        //对象池父节点
        private Transform m_PoolParent;
    
        //对象池字典
        private Dictionary<string, PoolBase> m_Pools = new Dictionary<string, PoolBase>();
    
        private void Awake()
        {
            m_PoolParent = this.transform.parent.Find("Pool");
        }
        
        //创建对象池,,T必须是继承PoolBase的类型
        private void CreatePool<T>(string poolName, float releaseTime) where T : PoolBase
        {
            if (!m_Pools.TryGetValue(poolName, out PoolBase pool))
            {
                GameObject go = new GameObject(poolName);
                go.transform.SetParent(m_PoolParent);
                pool = go.AddComponent<T>();
                pool.Init(releaseTime);
                m_Pools.Add(poolName, pool);
            }
        }
        
        //创建物体对象池
        public void CreateGameObjectPool(string poolName, float releaseTime)
        {
            CreatePool<GameObjectPool>(poolName, releaseTime);
        }
        
        //创建资源对象池
        public void CreateAssetPool(string poolName, float releaseTime)
        {
            CreatePool<AssetPool>(poolName, releaseTime);
        }
    
    	//取出对象
        public Object Spawn(string poolName, string assetName)
        {
            if (m_Pools.TryGetValue(poolName, out PoolBase pool))
            {
                return pool.Spawn(assetName);
            }
            return null;
        }
        
        //回收对象
        public void UnSpawn(string poolName, string assetName, Object asset)
        {
            if (m_Pools.TryGetValue(poolName, out PoolBase pool))
            {
                pool.UnSpawn(assetName, asset);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    image.png

    private static PoolManager _pool;
    public static PoolManager Pool
    {
        get { return _pool; }
    }
    
    public void Awake()
    {
        _resource = this.gameObject.AddComponent<ResourceManager>();
        _lua = this.gameObject.AddComponent<LuaManager>();
        _ui = this.gameObject.AddComponent<UIManager>();
        _entity = this.gameObject.AddComponent<EntityManager>();
        _scene = this.gameObject.AddComponent<MySceneManager>();
        _sound = this.gameObject.AddComponent<SoundManager>();
        _event = this.gameObject.AddComponent<EventManager>();
        _pool = this.gameObject.AddComponent<PoolManager>();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    13-2. 对象池测试

    Lua的脚本中编写逻辑。调用Manager.UI.OpenUI(“”),OpenUI函数时UIManager中的打开UI功能,函数内部去对象池查找,有就Spawn没有就加载Bundle后LoadUI;调用self:Close()关闭UI,这个self是UILogic,因为OpenUI函数传进去一个ui.TestUI用于Init,并连接到执行了Init这个功能的脚本UILogic(继承了LuaBehaviour),从而在TestUI脚本中用self就是UILogic的实例。

    public class UILogic : LuaBehaviour
    {
        public string AssetName;
        Action m_LuaOnOpen;
        Action m_LuaOnClose;
        public override void Init(string luaName)
        {
            base.Init(luaName);
            m_ScriptEnv.Get("OnOpen", out m_LuaOnOpen);
            m_ScriptEnv.Get("OnClose", out m_LuaOnClose);
        }
        
        public void OnOpen()
        {
            m_LuaOnOpen?.Invoke();
        }
    
        public void OnClose()
        {
            m_LuaOnClose?.Invoke();
            //回收对象,把这个带有UILogic的物体直接放进对象池。
            Manager.Pool.UnSpawn("UI", AssetName, this.gameObject);
        }
        protected override void Clear()
        {
            //OnClose();
            base.Clear();
            m_LuaOnOpen = null;
            m_LuaOnClose = null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class UIManager : MonoBehaviour
    {
        缓存UI,,后期会用对象池管理,,,不需要了
        //Dictionary m_UI = new Dictionary();
    
        //UI分组
        Dictionary<string, Transform> m_UIGroups = new Dictionary<string, Transform>();
    
        private Transform m_UIParent;
    
        /// 
        /// 传入一个ui名字和lua名字,以及ui要放到的组中,自动给ui预制体绑定C#脚本,自动执行lua脚本
        /// 
        /// ui名字
        /// lua名字
        public void OpenUI(string uiName, string group, string luaName)
        {
            GameObject ui = null;
            //加载ui成功后,设置父节点
            Transform parent = GetUIGroup(group);
    
            //去对象池查找,如果有ui就直接加载,没有再去Load
            string uiPath = PathUtil.GetUIPath(uiName);
            Object uiObj = Manager.Pool.Spawn("UI",uiPath);
            if (uiObj != null)
            {
                ui = uiObj as GameObject;
    			ui.transform.SetParent(parent, false);
                UILogic uiLogic = ui.GetComponent<UILogic>();
                uiLogic.OnOpen();
                return;
            }
    
            Manager.Resource.LoadUI(uiName, (UnityEngine.Object obj) =>
            {
                ui = Instantiate(obj) as GameObject;
    			ui.transform.SetParent(parent, false);
    			//m_UI.Add(uiName, ui);
                if (ui.name.Contains("TestUI"))
                {
                    UISelect uiSelect = ui.transform.GetChild(0).GetChild(1).gameObject.AddComponent<UISelect>();
                    uiSelect.Init("ui.SelectMenuUI");
                    uiSelect.OnOpen();
    
                    OptionsSelect optionsSelect = ui.transform.GetChild(1).gameObject.AddComponent<OptionsSelect>();
                    optionsSelect.Init("ui.SelectOptions");
                    optionsSelect.OnOpen();
                }
    
                //给UI预制体绑定UILogic的C#脚本
                UILogic uiLogic = ui.AddComponent<UILogic>();
                uiLogic.AssetName = uiPath;
                //初始化这个lua脚本(Awake)
                uiLogic.Init(luaName);
                //UI的Start
                uiLogic.OnOpen();
            });
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    public class GameStart : MonoBehaviour
    {
        public GameMode GameMode;
    
        // Start is called before the first frame update
        void Start()
        {
            //开始时订阅事件
            Manager.Event.Subscribe(10000, OnLuaInit);
            
            AppConst.GameMode = this.GameMode;
            DontDestroyOnLoad(this);
    
            Manager.Resource.ParseVersionFile();
            Manager.Lua.Init();
        }
    
        void OnLuaInit(object args)
        {
            //初始化完成之后(lua都加载完),在执行回调
            Manager.Lua.StartLua("main"); //输入的文件名
            //输入的是函数名
            XLua.LuaFunction func = Manager.Lua.LuaEnv.Global.Get<XLua.LuaFunction>("Main");
            func.Call();
            
            Manager.Pool.CreateGameObjectPool("UI", 10);
            Manager.Pool.CreateGameObjectPool("Monster", 120);
            Manager.Pool.CreateGameObjectPool("Effect", 120);
            Manager.Pool.CreateAssetPool("AssetBundle", 300);
        }
    
        public void OnApplicationQuit()
        {
            Manager.Event.UnSubscribe(10000, OnLuaInit);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    btn_pooltest = self.transform:Find("amiibo"):GetComponent("Button");
    btn_close = self.transform:Find("DLC Purchased"):GetComponent("Button");
    btn_pooltest:OnClickSet(
            function()
                Manager.UI:OpenUI("TestUI", "UI", "ui.TestUI");
            end
    )
    
    btn_close:OnClickSet(
            function()
                self:Close();
            end
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    13-3. AssetBundle卸载

    需要给Bundle资源添加引用计数,当没有使用的时候,就卸载bundle
    image.pngimage.png
    逻辑:加载资源,ResourceManager.LoadBundleAsync加引用计数,当GameObjectPool把不用的物体release时需要调用ResourceManager.MinusBundleCount减去该物体资源的引用计数,当引用计数<=0时,放到对象池release,其中调用Manager.Resource.UnloadBundle卸载资源。

    public class ResourceManager : MonoBehaviour
    {
        //定义一个类,用来解析版本信息
        internal class BundleInfo
        {
            public string AssetName;
            public string BundleName;
            public List<string> Dependeces;
        }
    
        internal class BundleData
        {
            public AssetBundle Bundle;
            
            //引用计数
            public int Count;
    
            public BundleData(AssetBundle ab)
            {
                Bundle = ab;
                Count = 1;
            }
        }
        
        //存放bundle信息的集合
        private Dictionary<string, BundleInfo> m_BundleInfos = new Dictionary<string, BundleInfo>();
        //存放加载过的Bundle
        //private Dictionary m_AssetBundles = new Dictionary();
        private Dictionary<string, BundleData> m_AssetBundles = new Dictionary<string, BundleData>();
    
        IEnumerator LoadBundleAsync(string assetName,Action<UObject> action = null)
        {
            string bundleName = m_BundleInfos[assetName].BundleName;
            //这个是小写的bundle.ab的路径名
            string bundlePath = Path.Combine(PathUtil.BundleResourcePath, bundleName);
            List<string> dependences = m_BundleInfos[assetName].Dependeces;
            //判断是否已经加载过bundle了
            BundleData bundle = GetBundle(bundleName);
            if (bundle == null)
            {
                //如果没有取到就要去对象池取
                UObject obj = Manager.Pool.Spawn("AssetBundle", bundleName);
                if (obj != null)
                {
                    AssetBundle ab = obj as AssetBundle;
                    bundle = new BundleData(ab);
                }
                else//如果对象池没取到,就去加载bundle
                {
                    //创建异步加载bundle申请
                    AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(bundlePath);
                    yield return request;
                    bundle = new BundleData(request.assetBundle);
                }
                m_AssetBundles.Add(bundleName, bundle);
            }
    
    		//先加载需要的Bundle,然后检测依赖资源,如果依赖资源也卸载掉了,就加载依赖资源
            if (dependences != null && dependences.Count > 0)
            {
                //递归加载依赖bundle,因为依赖的资源目录名就是bundle资源名
                for (int i = 0; i < dependences.Count; i++)
                {
                    yield return LoadBundleAsync(dependences[i]);
                }
            }
    
            if (assetName.EndsWith(".unity"))
            {
                action?.Invoke(null);
                yield break;
            }
    
    		//如果action == null,说明是依赖资源,依赖资源不需要加载asset,也不需要执行回调
            if (action == null)
            {
                yield break;
            }
    
            //从bundle申请加载指定路径名的文件,例如prefab
            AssetBundleRequest bundleRequest = bundle.Bundle.LoadAssetAsync(assetName);
            yield return bundleRequest;
    
            //如果回调和request都不为空,语法糖
            action?.Invoke(bundleRequest?.asset);
        }
    
        //从已经加载的Bundle字典中查询是否已经有了
        BundleData GetBundle(string name)
        {
            BundleData bundle = null;
            if (m_AssetBundles.TryGetValue(name, out bundle))
            {
                //拿到了BundleData说明要使用了
                bundle.Count++;
                return bundle;
            }
            return null;
        }
    
        public void UnloadBundle(string name)
        {
            
        }
    
        //减去一个bundle的引用计数
        private void MinusOneBundleCount(string bundleName)
        {
            if (m_AssetBundles.TryGetValue(bundleName, out BundleData bundle))
            {
                if (bundle.Count > 0)
                {
                    bundle.Count--;
                    Debug.Log("bundle引用计数:" + bundleName + " count:" + bundle.Count);
                }
    
                if (bundle.Count <= 0)
                {
                     Debug.Log("放入bundle对象池:" + bundleName);
                     Manager.Pool.UnSpawn("AssetBundle", bundleName, bundle.Bundle);
                     m_AssetBundles.Remove(bundleName);
                }
            }
        }
        
        //减去Bundle和依赖资源的引用计数
        public void MinusBundleCount(string assetName)
        {
            //先减掉自身的bundle引用计数
            string bundleName = m_BundleInfos[assetName].BundleName;
            MinusOneBundleCount(bundleName);
            
            //依赖资源,,在查找依赖资源,减掉依赖资源的引用计数
            List<string> dependences = m_BundleInfos[assetName].Dependeces;
            if (dependences != null)
            {
                foreach (string dependence in dependences)
                {
                    string name = m_BundleInfos[dependence].BundleName;
                    MinusOneBundleCount(name);
                }
            }
        }
    
    	//卸载assetbundle资源
        public void UnloadBundle(UObject obj)
        {
            AssetBundle ab = obj as AssetBundle;
            ab.Unload(true);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    public override void Release()
    {
        base.Release();
        foreach (PoolObject item in m_Objects)
        {
            if (System.DateTime.Now.Ticks - item.LastUseTime.Ticks >= m_ReleaseTime * 10000000)
            {
                Debug.Log("GameObjectPool release time:" + System.DateTime.Now);
                Destroy(item.Object);
                Manager.Resource.MinusBundleCount(item.Name);
                m_Objects.Remove(item);
                //因为删除了list一项之后,不能用迭代器了,需要递归一下跳出
                Release();
                return;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    public override void Release()
    {
        base.Release();
        foreach (PoolObject item in m_Objects)
        {
            if (System.DateTime.Now.Ticks - item.LastUseTime.Ticks >= m_ReleaseTime * 10000000)
            {
                Debug.Log("AssetPool release time:" + System.DateTime.Now + "unload ab:" + item.Name);
                Manager.Resource.UnloadBundle(item.Object);
                m_Objects.Remove(item);
                Release();
                return;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

  • 相关阅读:
    Docker容器化技术
    【MySQL】MySQL数据库锁使用与InnoDB加锁的原理解析
    Redis篇 String的基本命令
    Qt工具开发,该不该跳槽?
    Ubuntu 20.04 中配置NFS服务
    一文读懂SQL的增删改查(基础教程)
    C++程序设计期末考试复习试题及解析 3(自用~)
    从猿六年---C++笔试\面试的不成熟小建议来啦
    原码反码补码移码的介绍和计算
    温故知新:探究Android UI 绘制刷新流程
  • 原文地址:https://blog.csdn.net/weixin_42264818/article/details/128211412