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
m_InstancePool = objectPoolManager.CreateSingleSpawnObjectPool<EntityInstanceObject>(Utility.Text.Format("Entity Instance Pool ({0})", name), instanceCapacity, instanceExpireTime, instancePriority);
AssetPool与ResourceObject
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
/// <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
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
m_DependencyResources.Add(dependencyResource);
何时引用-1
bundle被释放时,子依赖bundle引用-1
GameFramework.Resource.ResourceManager.ResourceLoader.ResourceObject.Release
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
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
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
m_ResourceLoader.m_ResourcePool.Unspawn(m_Resource);
AssetObject
何时引用+1
assetA新加载完成时,创建AssetObjectA,把子依赖asset引用+1
GameFramework.Resource.ResourceManager.ResourceLoader.AssetObject.Create
//所有依赖的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
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
//从对象池里拿一个 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
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
/// <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中获取,还是异步加载完成
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),释放内存
posted on 2023-08-24 21:03 luoyikun 阅读(378) 评论(0) 编辑 收藏 举报 来源
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2021-08-24 lua面向对象:new,继承,多态