Unity3d:GameFramework解析:實(shí)體,對(duì)象池,資源管理,獲取計(jì)數(shù),引用計(jì)數(shù),自動(dòng)釋放
基本概念
1.GF萬(wàn)物基于引用池IReference
2.ObjectBase : IReference類(lèi)的m_Target持有unity中Mono,資源,GameObejct
3.AssetObject : ObjectBase類(lèi)m_Target持有Assetbundle中的Asset,具有獲取,引用兩個(gè)計(jì)數(shù)管理釋放
4.ResourceObject : ObjectBase類(lèi)m_Target持有Assetbundle,具有獲取,引用兩個(gè)計(jì)數(shù)管理釋放
5.EntityInstanceObject : ObjectBase類(lèi)m_Target指向Assetbundle中的Asset實(shí)例化后的GameObject,內(nèi)部m_EntityAsset也是Assetbundle中的Asset
6.對(duì)象池具有按照間隔自動(dòng)釋放無(wú)用對(duì)象,對(duì)于實(shí)體,獲取為0,即無(wú)用對(duì)象;對(duì)于AssetObject,ResourceObject要獲取為0,父依賴(自己被別依賴)為0,即無(wú)用
7.引用的概念為資源被依賴,例如bundleA依賴bundleB,于是bundleB的引用=1
8.獲取的概念:針對(duì)資源為對(duì)象再派生(關(guān)聯(lián))出別的對(duì)象,例如ResourceObjectA派生出AssetObjectA,即ResourceObjectA獲取為1;AssetObjectA再派生出EntityInstanceObjectA,AssetObjectA的獲取為1
對(duì)象池創(chuàng)建
InstancePool
只能單獲取,即不能對(duì)一個(gè)對(duì)象反復(fù)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實(shí)體對(duì)象
1.每次使用看實(shí)體對(duì)象池中有無(wú),有是指存在空閑未使用實(shí)體對(duì)象,取出來(lái)用
2.沒(méi)有的話,需要從資源加載流程中走一遍
釋放時(shí)
UnityGameFramework.Runtime.DefaultEntityHelper.ReleaseEntity
/// <summary>
/// 釋放實(shí)體。
/// </summary>
/// <param name="entityAsset">要釋放的實(shí)體資源。</param>
/// <param name="entityInstance">要釋放的實(shí)體實(shí)例。</param>
public override void ReleaseEntity(object entityAsset, object entityInstance)
{
m_ResourceComponent.UnloadAsset(entityAsset);
Destroy((Object)entityInstance);
}
1.AssetPool中把entityAsset的獲取-1
2.銷(xiāo)毀asset實(shí)例出來(lái)的GameObject
ResourceObject
何時(shí)引用+1
在assetA加載完,assetA的依賴asset的bundle引用+1。注意是依賴的asset的bundle,自身的bundle并不會(huì)引用+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); //所有依賴這個(gè)asset的resource引用+1
}
同時(shí)被依賴的bundleB加入到主bundleA的ResourceObject依賴列表中
GameFramework.Resource.ResourceManager.ResourceLoader.ResourceObject.AddDependencyResource
m_DependencyResources.Add(dependencyResource);
何時(shí)引用-1
bundle被釋放時(shí),子依賴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;
//只會(huì)-1,不會(huì)對(duì)為 0 的Assetbundle進(jìn)行卸載
}
何時(shí)獲取+1
bundleA中獲取assetA時(shí),獲取+1。此時(shí)有有兩種情況,
1.執(zhí)行加載asset任務(wù)時(shí),主bundle已加載,從ResourcePool中獲取
GameFramework.Resource.ResourceManager.ResourceLoader.LoadResourceAgent.Start
ResourceObject resourceObject = m_ResourceLoader.m_ResourcePool.Spawn(resourceName);
if (resourceObject != null)
{
GameFrameworkLog.Info("ResourcePool獲取到了{(lán)0},說(shuō)明asset:{1}的bundle已經(jīng)加好了,返回bundle", resourceName, m_Task.AssetName);
//從resource對(duì)象池中取出,說(shuō)明之前加載過(guò)Assetbundle,任務(wù)可以接著執(zhí)行
OnResourceObjectReady(resourceObject);
return StartTaskStatus.CanResume;
}
2.bundle未加載,加載完后注冊(cè)入對(duì)象池,獲取+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);
}
何時(shí)獲取-1
GameFramework.Resource.ResourceManager.ResourceLoader.AssetObject.Release
m_ResourceLoader.m_ResourcePool.Unspawn(m_Resource);
AssetObject
何時(shí)引用+1
assetA新加載完成時(shí),創(chuàng)建AssetObjectA,把子依賴asset引用+1
GameFramework.Resource.ResourceManager.ResourceLoader.AssetObject.Create
//所有依賴的asset 引用+1,它自己次數(shù)不會(huì)+1
foreach (object dependencyAsset in dependencyAssets)
{
int referenceCount = 0;
GameFrameworkLog.Info("AssetObject創(chuàng)建-->{0}引用次數(shù)+1", dependencyAsset);
if (resourceLoader.m_AssetDependencyCount.TryGetValue(dependencyAsset, out referenceCount))
{
resourceLoader.m_AssetDependencyCount[dependencyAsset] = referenceCount + 1;
}
else
{
resourceLoader.m_AssetDependencyCount.Add(dependencyAsset, 1);
}
}
何時(shí)引用-1
AssetObjectA釋放時(shí),把所有子依賴資源-1。這里只會(huì)找直接子依賴(子節(jié)點(diǎn)),不會(huì)找到孫節(jié)點(diǎn)上
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
}
何時(shí)獲取+1
AssetObject的獲取,是為了給實(shí)例對(duì)象實(shí)例化。兩種情況下
1.任務(wù)執(zhí)行時(shí),AssetPool有,直接返回,獲取+1
GameFramework.Resource.ResourceManager.ResourceLoader.LoadResourceAgent.Start
//從對(duì)象池里拿一個(gè)
AssetObject assetObject = m_ResourceLoader.m_AssetPool.Spawn(m_Task.AssetName);
if (assetObject != null)
{
//說(shuō)明資源之前加載過(guò),且在AssetObject緩存池中
//一旦成功執(zhí)行Spawn,Spawn+1,在釋放資源時(shí)不為0會(huì)跳過(guò)
GameFrameworkLog.Info("AssetPool獲取到了{(lán)0},不需要加載,直接返回asset", m_Task.AssetName);
//如果是實(shí)體,實(shí)例化asset,并且新建一個(gè)實(shí)體對(duì)象
OnAssetObjectReady(assetObject);
return StartTaskStatus.Done;
}
2.AssetPool沒(méi)有,從Assetbundle中加載完成asset,創(chuàng)建新AssetObject,并注冊(cè)進(jìn)入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}加載完成,并且創(chuàng)建AssetObject到m_AssetPool緩沖池中", m_Task.AssetName);
m_ResourceLoader.m_AssetPool.Register(assetObject, true);
何時(shí)獲取-1
EntityInstanceObject釋放時(shí)
UnityGameFramework.Runtime.DefaultEntityHelper.ReleaseEntity
/// <summary>
/// 釋放實(shí)體。
/// </summary>
/// <param name="entityAsset">要釋放的實(shí)體資源。</param>
/// <param name="entityInstance">要釋放的實(shí)體實(shí)例。</param>
public override void ReleaseEntity(object entityAsset, object entityInstance)
{
m_ResourceComponent.UnloadAsset(entityAsset);
Destroy((Object)entityInstance);
}
加載實(shí)體創(chuàng)建各個(gè)asset任務(wù)
加載一個(gè)實(shí)體,一個(gè)asset作為主任務(wù),asset依賴的各個(gè)asset作為依賴任務(wù)

單個(gè)asest任務(wù)加載任務(wù)執(zhí)行

任務(wù)
任務(wù)派生LoadAssetTask,LoadDependencyAssetTask,LoadSceneTask
任務(wù)完成的標(biāo)志
資源準(zhǔn)備好,即任務(wù)完成。不管是是從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;
}
自動(dòng)釋放
隱藏某實(shí)體時(shí),在對(duì)象池自動(dòng)釋放中,如果改實(shí)體池依賴的asset獲取為0,再判斷出bundle獲取為0,觸發(fā)assetbundle.Unload(true),釋放內(nèi)存

posted on 2023-08-24 21:03 luoyikun 閱讀(586) 評(píng)論(0) 收藏 舉報(bào) 來(lái)源
浙公網(wǎng)安備 33010602011771號(hào)