前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Unity3d:GameFramework解析:实体,对象池,资源管理,获取计数,引用计数,自动释放

Unity3d:GameFramework解析:实体,对象池,资源管理,获取计数,引用计数,自动释放

作者头像
立羽
发布2023-08-25 12:56:49
4990
发布2023-08-25 12:56:49
举报
文章被收录于专栏:Unity3d程序开发Unity3d程序开发

基本概念

1.GF万物基于引用池IReference 2.ObjectBase : IReference类的m_Target持有unity中Mono,资源,GameObejct 3.AssetObject : ObjectBase类m_Target持有Assetbundle中的Asset,具有获取,引用两个计数管理释放 4.ResourceObject : ObjectBase类m_Target持有Assetbundle,具有获取,引用两个计数管理释放 5.EntityInstanceObject : ObjectBase类m_Target指向Assetbundle中的Asset实例化后的GameObject,内部m_EntityAsset也是Assetbundle中的Asset 6.对象池具有按照间隔自动释放无用对象,对于实体,获取为0,即无用对象;对于AssetObject,ResourceObject要获取为0,父依赖(自己被别依赖)为0,即无用 7.引用的概念为资源被依赖,例如bundleA依赖bundleB,于是bundleB的引用=1 8.获取的概念:针对资源为对象再派生(关联)出别的对象,例如ResourceObjectA派生出AssetObjectA,即ResourceObjectA获取为1;AssetObjectA再派生出EntityInstanceObjectA,AssetObjectA的获取为1

对象池创建

InstancePool

只能单获取,即不能对一个对象反复Spawn

代码语言:javascript
复制
m_InstancePool = objectPoolManager.CreateSingleSpawnObjectPool<EntityInstanceObject>(Utility.Text.Format("Entity Instance Pool ({0})", name), instanceCapacity, instanceExpireTime, instancePriority);

AssetPool与ResourceObject

代码语言:javascript
复制
public void SetObjectPoolManager(IObjectPoolManager objectPoolManager)
{
    m_AssetPool = objectPoolManager.CreateMultiSpawnObjectPool<AssetObject>("Asset Pool");
    m_ResourcePool = objectPoolManager.CreateMultiSpawnObjectPool<ResourceObject>("Resource Pool");
}

EntityInstanceObject实体对象

1.每次使用看实体对象池中有无,有是指存在空闲未使用实体对象,取出来用 2.没有的话,需要从资源加载流程中走一遍

释放时

UnityGameFramework.Runtime.DefaultEntityHelper.ReleaseEntity

代码语言:javascript
复制
        /// <summary>
        /// 释放实体。
        /// </summary>
        /// <param name="entityAsset">要释放的实体资源。</param>
        /// <param name="entityInstance">要释放的实体实例。</param>
        public override void ReleaseEntity(object entityAsset, object entityInstance)
        {
            m_ResourceComponent.UnloadAsset(entityAsset);
            Destroy((Object)entityInstance);
        }

1.AssetPool中把entityAsset的获取-1 2.销毁asset实例出来的GameObject

ResourceObject

何时引用+1

在assetA加载完,assetA的依赖asset的bundle引用+1。注意是依赖的asset的bundle,自身的bundle并不会引用+1 GameFramework.Resource.ResourceManager.ResourceLoader.LoadResourceAgent.OnLoadResourceAgentHelperLoadComplete

代码语言:javascript
复制
foreach (object dependencyAsset in dependencyAssets)
{
    object dependencyResource = null;
    if (m_ResourceLoader.m_AssetToResourceMap.TryGetValue(dependencyAsset, out dependencyResource))
    {
        m_Task.ResourceObject.AddDependencyResource(dependencyResource); //所有依赖这个asset的resource引用+1
    }

同时被依赖的bundleB加入到主bundleA的ResourceObject依赖列表中 GameFramework.Resource.ResourceManager.ResourceLoader.ResourceObject.AddDependencyResource

代码语言:javascript
复制
m_DependencyResources.Add(dependencyResource);

何时引用-1

bundle被释放时,子依赖bundle引用-1 GameFramework.Resource.ResourceManager.ResourceLoader.ResourceObject.Release

代码语言:javascript
复制
 foreach (object dependencyResource in m_DependencyResources)
{
    int referenceCount = 0;
    if (m_ResourceLoader.m_ResourceDependencyCount.TryGetValue(dependencyResource, out referenceCount))
    {
        m_ResourceLoader.m_ResourceDependencyCount[dependencyResource] = referenceCount - 1;
        //只会-1,不会对为 0 的Assetbundle进行卸载
    }

何时获取+1

bundleA中获取assetA时,获取+1。此时有有两种情况, 1.执行加载asset任务时,主bundle已加载,从ResourcePool中获取 GameFramework.Resource.ResourceManager.ResourceLoader.LoadResourceAgent.Start

代码语言:javascript
复制
ResourceObject resourceObject = m_ResourceLoader.m_ResourcePool.Spawn(resourceName);
if (resourceObject != null)
{
    GameFrameworkLog.Info("ResourcePool获取到了{0},说明asset:{1}的bundle已经加好了,返回bundle", resourceName, m_Task.AssetName);
    //从resource对象池中取出,说明之前加载过Assetbundle,任务可以接着执行
    OnResourceObjectReady(resourceObject);
    return StartTaskStatus.CanResume;
}

2.bundle未加载,加载完后注册入对象池,获取+1 GameFramework.Resource.ResourceManager.ResourceLoader.LoadResourceAgent.OnLoadResourceAgentHelperReadFileComplete

代码语言:javascript
复制
private void OnLoadResourceAgentHelperReadFileComplete(object sender, LoadResourceAgentHelperReadFileCompleteEventArgs e)
{
    GameFrameworkLog.Info("Assetbundle加载完成:{0}", m_Task.ResourceInfo.ResourceName.Name);
    ResourceObject resourceObject = ResourceObject.Create(m_Task.ResourceInfo.ResourceName.Name, e.Resource, m_ResourceHelper, m_ResourceLoader);
    m_ResourceLoader.m_ResourcePool.Register(resourceObject, true);
    s_LoadingResourceNames.Remove(m_Task.ResourceInfo.ResourceName.Name);
    OnResourceObjectReady(resourceObject);
}

何时获取-1

GameFramework.Resource.ResourceManager.ResourceLoader.AssetObject.Release

代码语言:javascript
复制
m_ResourceLoader.m_ResourcePool.Unspawn(m_Resource);

AssetObject

何时引用+1

assetA新加载完成时,创建AssetObjectA,把子依赖asset引用+1 GameFramework.Resource.ResourceManager.ResourceLoader.AssetObject.Create

代码语言:javascript
复制
//所有依赖的asset 引用+1,它自己次数不会+1
foreach (object dependencyAsset in dependencyAssets)
{
    int referenceCount = 0;
    GameFrameworkLog.Info("AssetObject创建-->{0}引用次数+1", dependencyAsset);
    if (resourceLoader.m_AssetDependencyCount.TryGetValue(dependencyAsset, out referenceCount))
    {
        resourceLoader.m_AssetDependencyCount[dependencyAsset] = referenceCount + 1;
    }
    else
    {
        resourceLoader.m_AssetDependencyCount.Add(dependencyAsset, 1);
    }
}

何时引用-1

AssetObjectA释放时,把所有子依赖资源-1。这里只会找直接子依赖(子节点),不会找到孙节点上 GameFramework.Resource.ResourceManager.ResourceLoader.AssetObject.Release

代码语言:javascript
复制
foreach (object dependencyAsset in m_DependencyAssets)
{
    int referenceCount = 0;
    if (m_ResourceLoader.m_AssetDependencyCount.TryGetValue(dependencyAsset, out referenceCount))
    {
        m_ResourceLoader.m_AssetDependencyCount[dependencyAsset] = referenceCount - 1;
        //子依赖的asset -1
    }

何时获取+1

AssetObject的获取,是为了给实例对象实例化。两种情况下 1.任务执行时,AssetPool有,直接返回,获取+1 GameFramework.Resource.ResourceManager.ResourceLoader.LoadResourceAgent.Start

代码语言:javascript
复制
//从对象池里拿一个 
AssetObject assetObject = m_ResourceLoader.m_AssetPool.Spawn(m_Task.AssetName);
if (assetObject != null)
{
    //说明资源之前加载过,且在AssetObject缓存池中
    //一旦成功执行Spawn,Spawn+1,在释放资源时不为0会跳过
    GameFrameworkLog.Info("AssetPool获取到了{0},不需要加载,直接返回asset", m_Task.AssetName);
    //如果是实体,实例化asset,并且新建一个实体对象
    OnAssetObjectReady(assetObject);
    return StartTaskStatus.Done;
}

2.AssetPool没有,从Assetbundle中加载完成asset,创建新AssetObject,并注册进入AssetPool,获取+1 GameFramework.Resource.ResourceManager.ResourceLoader.LoadResourceAgent.OnLoadResourceAgentHelperLoadComplete

代码语言:javascript
复制
            assetObject = AssetObject.Create(m_Task.AssetName, e.Asset, dependencyAssets, m_Task.ResourceObject.Target, m_ResourceHelper, m_ResourceLoader);
            GameFrameworkLog.Info("asset-->{0}加载完成,并且创建AssetObject到m_AssetPool缓冲池中", m_Task.AssetName);
            m_ResourceLoader.m_AssetPool.Register(assetObject, true);

何时获取-1

EntityInstanceObject释放时 UnityGameFramework.Runtime.DefaultEntityHelper.ReleaseEntity

代码语言:javascript
复制
        /// <summary>
        /// 释放实体。
        /// </summary>
        /// <param name="entityAsset">要释放的实体资源。</param>
        /// <param name="entityInstance">要释放的实体实例。</param>
        public override void ReleaseEntity(object entityAsset, object entityInstance)
        {
            m_ResourceComponent.UnloadAsset(entityAsset);
            Destroy((Object)entityInstance);
        }

加载实体创建各个asset任务

加载一个实体,一个asset作为主任务,asset依赖的各个asset作为依赖任务

在这里插入图片描述
在这里插入图片描述

单个asest任务加载任务执行

在这里插入图片描述
在这里插入图片描述

任务

任务派生LoadAssetTask,LoadDependencyAssetTask,LoadSceneTask

任务完成的标志

资源准备好,即任务完成。不管是是从AssetPool中获取,还是异步加载完成

代码语言:javascript
复制
private void OnAssetObjectReady(AssetObject assetObject)
{
    m_Helper.Reset();

    object asset = assetObject.Target;
    if (m_Task.IsScene)
    {
        m_ResourceLoader.m_SceneToAssetMap.Add(m_Task.AssetName, asset);
    }

    m_Task.OnLoadAssetSuccess(this, asset, (float)(DateTime.UtcNow - m_Task.StartTime).TotalSeconds);
    m_Task.Done = true;
}

自动释放

隐藏某实体时,在对象池自动释放中,如果改实体池依赖的asset获取为0,再判断出bundle获取为0,触发assetbundle.Unload(true),释放内存

在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-08-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本概念
  • 对象池创建
    • InstancePool
      • AssetPool与ResourceObject
      • EntityInstanceObject实体对象
        • 释放时
        • ResourceObject
          • 何时引用+1
            • 何时引用-1
              • 何时获取+1
                • 何时获取-1
                • AssetObject
                  • 何时引用+1
                    • 何时引用-1
                      • 何时获取+1
                        • 何时获取-1
                        • 加载实体创建各个asset任务
                        • 单个asest任务加载任务执行
                        • 任务
                          • 任务完成的标志
                          • 自动释放
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档