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

基本概念

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

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

AssetPool与ResourceObject

csharp 复制代码
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

csharp 复制代码
        /// <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

csharp 复制代码
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

csharp 复制代码
m_DependencyResources.Add(dependencyResource);

何时引用-1

bundle被释放时,子依赖bundle引用-1

GameFramework.Resource.ResourceManager.ResourceLoader.ResourceObject.Release

csharp 复制代码
 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

csharp 复制代码
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

csharp 复制代码
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

csharp 复制代码
m_ResourceLoader.m_ResourcePool.Unspawn(m_Resource);

AssetObject

何时引用+1

assetA新加载完成时,创建AssetObjectA,把子依赖asset引用+1

GameFramework.Resource.ResourceManager.ResourceLoader.AssetObject.Create

csharp 复制代码
//所有依赖的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

csharp 复制代码
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

csharp 复制代码
//从对象池里拿一个 
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

csharp 复制代码
            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

csharp 复制代码
        /// <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中获取,还是异步加载完成

csharp 复制代码
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),释放内存

相关推荐
北桥苏1 天前
如何在 Unity3D 导入 Spine 动画
unity3d
Thomas游戏开发3 天前
Unity3D状态管理器实现指南
前端框架·unity3d·游戏开发
土豆宝8 天前
Unity Visual Scripting(可视化脚本) 自定义节点 踩坑教程
unity3d
Thomas游戏开发9 天前
Unity3D光照层级与动态切换指南
前端框架·unity3d·游戏开发
Thomas游戏开发20 天前
Unity3D 崩溃分析工具的集成与优化
前端框架·unity3d·游戏开发
Thomas游戏开发24 天前
Unity3D网格简化与LOD技术详解
前端框架·unity3d·游戏开发
Thomas_YXQ25 天前
Unity3D 图形渲染(Graphics & Rendering)详解
开发语言·unity·图形渲染·unity3d·shader
Thomas游戏开发1 个月前
Unity3D 图形渲染(Graphics & Rendering)详解
前端·unity3d·游戏开发
Thomas游戏开发1 个月前
Unity3D 光栅化 vs 光线追踪:技术详解
前端框架·unity3d·游戏开发
Thomas游戏开发1 个月前
Unity3D 多线程与协程优化详解
前端框架·unity3d·游戏开发