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),释放内存

相关推荐
Thomas游戏开发7 小时前
Unity3D 逻辑服的Entity, ComponentData与System划分详解
前端框架·unity3d·游戏开发
大眼睛姑娘1 天前
unity运行状态下移动、旋转、缩放控制模型
unity3d
青云交2 天前
大数据新视界 -- Impala 性能优化:分布式环境中的优化新视野(下)(28 / 30)
大数据·性能优化·资源管理·impala·优化策略·分布式环境·数据布局
暴走的锅巴7 天前
由C#委托回调想到的二三事
c#·gc·委托·垃圾回收·资源管理·资源释放·delegate
lin zaixi()13 天前
手把手教你写Unity3D飞机大战(2)天空盒布置
unity3d
Thomas_YXQ18 天前
Unity3D中管理Shader效果详解
开发语言·游戏·unity·unity3d·游戏开发
羊羊203518 天前
线性代数:Matrix2x2和Matrix3x3
线性代数·数学建模·unity3d
天人合一peng23 天前
Unity hub登录时一直无法进入license
unity3d
天涯学馆25 天前
Three.js灯光阴影与动画交互
前端·unity3d·three.js
Cool-浩1 个月前
Unity3D 开发技巧
开发语言·前端·unity·c#·unity3d·实用技巧·unity开发教程