资源管理(22)实例和资源实体建立关联,动态回池分类资源实体,并释放内存资源

 Instance是用Asset克隆出来的

ResourceEntity描述的是在内存种的信息,窗体是通过ResourceEntity的Target来克隆出来的,两者的对应关系存在InstanceReourceDic中,每克隆出一个实体,就存在一个Id

 

资源实体的依赖关系,通过Assetinfo.json解析出来的是AssetEntity,就是下面的信息,只是存的信息

/// <summary>
/// Asset实体
/// </summary>
public class AssetEntity
{
    /// <summary>
    /// 资源分类
    /// </summary>
    public AssetCategory Category;

    /// <summary>
    /// 资源名称
    /// </summary>
    public string AssetName;

    /// <summary>
    /// 资源完整名称(路径)
    /// </summary>
    public string AssetFullName;

    /// <summary>
    /// 所属资源包(这个资源在哪一个Assetbundle里)
    /// </summary>
    public string AssetBundleName;
    
    /// <summary>
    /// 依赖资源
    /// </summary>
    public List<AssetDependsEntity> DependsAssetList;
}

ResourceEntity,是从bundle中load出来的对象,存的具体的内容,比如资源被引用了多少次,上次使用的时间,关联的目标

/// <summary>
    /// 资源实体(AssetBundle和Asset)
    /// </summary>
    public class ResourceEntity
    {
        /// <summary>
        /// 资源名称
        /// </summary>
        public string ResourceName;

        /// <summary>
        /// 资源分类(用于Asset)
        /// </summary>
        public AssetCategory Category;

        /// <summary>
        /// 是否AssetBundle
        /// </summary>
        public bool IsAssetBundle;

        /// <summary>
        /// 关联目标
        /// </summary>
        public object Target;

        /// <summary>
        /// 上次使用时间
        /// </summary>
        private float m_LastUseTime;

        /// <summary>
        /// 引用计数
        /// </summary>
        public int ReferenceCount { get; private set; }

        /// <summary>
        /// 依赖的资源实体链表
        /// </summary>
        public LinkedList<ResourceEntity> DependsResourceList { get; private set; }

        public ResourceEntity()
        {
            DependsResourceList = new LinkedList<ResourceEntity>();
        }

        /// <summary>
        /// 对象取池
        /// </summary>
        public void Spawn()
        {
            //取池的时候设置一下最后使用时间
            m_LastUseTime = Time.time;

            if (!IsAssetBundle)
            {
                //如果不是assetbundle,引用计数加1
                ReferenceCount++;
            }
            else
            {
                //如果是锁定的资源包 不释放
                if (GameEntry.Pool.CheckAssetBundleIsLock(ResourceName))
                {
                    ReferenceCount = 1;
                }
            }
        }

        /// <summary>
        /// 对象回池
        /// </summary>
        public void Unspawn()
        {
            m_LastUseTime = Time.time;

            ReferenceCount--;
            if (ReferenceCount < 0)
            {
                ReferenceCount = 0;
            }
        }

        /// <summary>
        /// 对象是否可以释放
        /// </summary>
        /// <returns></returns>
        public bool GetCanRelease()
        {
            //引用计数为0,并且超出时间间隔
            if (ReferenceCount == 0 && Time.time - m_LastUseTime > GameEntry.Pool.ReleaseResourceInterval)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Release()
        {
            ResourceName = null;
            ReferenceCount = 0;

            if (IsAssetBundle)
            {
                //如果是assetbundle,Target关联的是Assetbundle,要执行bundle.Unload方法
                AssetBundle bundle = Target as AssetBundle;
                GameEntry.Log(LogCategory.Resource, "卸载了资源包", bundle.name);
                bundle.Unload(false);
            }
            Target = null;
            //把依赖的资源实体链表清空
            DependsResourceList.Clear();
            //同时把这个类对象也回池
            GameEntry.Pool.EnqueueClassObject(this);//当前资源实体回池
        }
    }

 加载的时候,把依赖资源加入到链表中,依赖资源数目+1,

 

 加载某个依赖资源完毕后,把依赖的资源实体放入临时链表,目的是加载依赖的时候,把依赖上的依赖也顺便返回。

把克隆出来的资源,加入到实例资源池中

 /// <summary>
        /// 打开UI窗口
        /// </summary>
        /// <param name="uiFormId">窗口Id</param>
        internal void OpenUIForm(int uiFormId, object userData, BaseAction<UIFormBase> onOpen)
        {
            //不能重复打开同一个UI窗口
            if (IsExists(uiFormId)) return;

            //1,读表
            Sys_UIFormEntity entity = GameEntry.DataTable.DataTableManager.Sys_UIFormDBModel.GetDic(uiFormId);
            if (entity == null)
            {
                List<Sys_UIFormEntity> lst = GameEntry.DataTable.DataTableManager.Sys_UIFormDBModel.GetList();
                Debug.LogError(uiFormId + "对应的UI窗口不存在");
                for (int i = 0; i < lst.Count; i++)
                {
                    Debug.LogError(lst[i].AssetPath_Chinese + "==" + lst[i].Id);
                }
                return;
            }

            UIFormBase formBase = GameEntry.UI.Dequeue(uiFormId);
            if (formBase == null)
            {
                //TODO:异步加载UI需要时间 此处需要处理过滤加载中的UI

                string assetPath = string.Empty;
                switch (GameEntry.Localization.CurrLanguage)
                {
                    case YouYouLanguage.Chinese:
                        assetPath = entity.AssetPath_Chinese;
                        break;
                    case YouYouLanguage.English:
                        assetPath = entity.AssetPath_English;
                        break;
                }

                //加载UI资源并克隆
                LoadUIAsset(assetPath, (GameObject uiObj) =>
                {
                    uiObj.SetParent(GameEntry.UI.GetUIGroup(entity.UIGroupId).Group);

                    formBase = uiObj.GetComponent<UIFormBase>();
                    formBase.Init(uiFormId, entity.UIGroupId, entity.DisableUILayer == 1, entity.IsLock == 1, userData);
                    m_OpenUIFormList.AddLast(formBase);

                    if (onOpen != null) onOpen(formBase);
                });
            }
            else
            {
                formBase.gameObject.SetActive(true);
                formBase.Open(userData);
                m_OpenUIFormList.AddLast(formBase);

                if (onOpen != null) onOpen(formBase);
            }
        }

        /// <summary>
        /// 加载UI资源并克隆
        /// </summary>
        /// <param name="assetPath"></param>
        /// <param name="onComplete"></param>
        private void LoadUIAsset(string assetPath, BaseAction<GameObject> onComplete)
        {
            GameEntry.Resource.ResourceLoaderManager.LoadMainAsset(AssetCategory.UIPrefab, string.Format("UI/UIPrefab/{0}.prefab", assetPath), (ResourceEntity resourcesEntity) =>
            {
                GameObject uiObj = Object.Instantiate((Object)resourcesEntity.Target) as GameObject;
                //把克隆出来的资源 加入实体资源池
                GameEntry.Pool.RegisterInstanceResource(uiObj.GetInstanceID(), resourcesEntity);

                if (onComplete != null) onComplete(uiObj);
            });
        }

PoolComPonent定义的实力资源字典

 

实例资源字典,注册,释放,释放的时候先释放依赖,

        #region 实例管理和分类资源池释放
        /// <summary>
        /// 实例字典(克隆出来的)
        /// </summary>
        private Dictionary<int, ResourceEntity> m_InstanceResourceDic;

        /// <summary>
        /// 注册到实例字典
        /// </summary>
        /// <param name="instanceId"></param>
        /// <param name="resourcesEntity"></param>
        internal void RegisterInstanceResource(int instanceId, ResourceEntity resourcesEntity)
        {
            GameEntry.Log(LogCategory.Resource, "注册到实例字典instanceId = {0}", instanceId);
            m_InstanceResourceDic[instanceId] = resourcesEntity;
        }

        /// <summary>
        /// 释放实例
        /// </summary>
        /// <param name="instanceId">实例Id</param>
        internal void ReleaseInstanceResource(int instanceId)
        {
            GameEntry.Log(LogCategory.Resource, "释放实例instanceId = {0}", instanceId);
            ResourceEntity resourceEntity = null;
            if (m_InstanceResourceDic.TryGetValue(instanceId, out resourceEntity))
            {
#if ASSETBUNDLE
                UnapawnResourceEntity(resourceEntity);            
#else
                resourceEntity.Target = null;
                GameEntry.Pool.EnqueueClassObject(resourceEntity);
#endif
                m_InstanceResourceDic.Remove(instanceId);
            }
        }
        /// <summary>
        /// 资源实体回池
        /// </summary>
        /// <param name="entity"></param>
        private void UnapawnResourceEntity(ResourceEntity entity)
        {
            //依赖资源实体 递归回池
            var curr = entity.DependsResourceList.First;
            while (curr != null)
            {
                UnapawnResourceEntity(curr.Value);
                curr = curr.Next;
            }

            //自身资源实体 回池
            GameEntry.Pool.PoolManager.AssetPool[entity.Category].Unspawn(entity.ResourceName);
        }

        #endregion

 

 

 

 

 

释放调用的地方

 

 

关闭界面之后, 先释放UI实例回池,释放类对象池,释放Assetbundle池,然后释放Asset池,时间调过,不是正常释放顺序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值