转自:https://blog.csdn.net/noahzuo/article/details/73565259数组
UObject
和FUObjectItem
UE4运行的基本单位是UObjet
,然而UObject
针对于内存相关的东西都储存在结构体FUObjectItem
中。有个全局变量GUObjectArray
,能够经过如下代码来遍历全部的Objects:函数
for (FRawObjectIterator It(false); It; ++It) { FUObjectItem* ObjectItem = *It; UObject* obj = ObjectItem->Object; }
能够经过以下代码来得到一个UObject
对应的ObjectItem
post
FUObjectItem* ObjectItem = GUObjectArray.ObjectToObjectItem(Object);
GUObjectArray中有几个函数能够经过索引和ObjectItem、Object的相互获取,对应的函数为IndexToObject、ObjectToIndex、IndexToObjectUnsafeForGC等。测试
GUObjectArray中全部的UObjectArray的分布是有顺序的——那些不会被GC的UObject,例如各StaticClass、核心Object,GamePlayInstance等会放在前面;而那些有可能被GC的UObject,则放在后面。此外,GUObjectArray中有个变量ObjLastNonGCIndex,用于分隔这两类UObject。this
/** * Returns true if this object is "disregard for GC"...same results as the legacy RF_DisregardForGC flag * * @param Object object to get for disregard for GC * @return true if this object si disregard for GC */ FORCEINLINE bool IsDisregardForGC(const class UObjectBase* Object) { return Object->InternalIndex <= ObjLastNonGCIndex; }
FUObjectCluster相关
Cluster指得是一组UObject为一簇,这群UObject同生共死,每一个Cluster有一个根root的UObject。spa
每个FUObjectItem里面有一个变量ClusterRootIndex,这个储存的是当前Object所在的Cluster的root object所在GUObjectArray的索引。.net
// UObjectArray.h // UObject Owner Cluster Index int32 ClusterRootIndex;
引擎中有一个全局变量FUObjectClusterContainer GUObjectClusters
,用于管理内存中全部的Clusters。指针
// Get the number of all clusters that have been allocated. GUObjectClusters.GetNumAllocatedClusters()
但很奇怪的,在我新建的若干个测试关卡/项目中,这个值一直为0……code
ULevel
不能够成为一个Cluster的root,缘由是在这个时候(postload以后)仍然有不少被Level引用的assets并未构建它们本身的Cluster。bool ULevel::CanBeClusterRoot() const { // We don't want to create the cluster for levels in the same place as other clusters (after PostLoad) // because at this point some of the assets referenced by levels may still haven't created clusters themselves. return false; }
虽然ULevel自己不能够做为Cluster Root,而相反的是它会建立一个特殊的actor container,用来储存本来应该位于Cluster的actors。这是因为只有某些特殊的actor种类才能用于Cluster,因此剩下的那些不能被cluster的actors须要经过actor container来进行引用。对象
ULevel中使用ClusterActors数组用于储存那些用于Cluster的Actors;用ActorsForGC储存那些剩下的Actors。主食中提到不但愿Level直接去引用那些本就是Cluster的Actors,注释中提到这会致使变慢(针对于cluster的Reference很慢,多是若是引用了cluster里面的actor,那么会致使整个cluster也会添加对应的引用关系,从而致使引用的层级变多吧……)
TArray<AActor*> ClusterActors; for (int32 ActorIndex = Actors.Num() - 1; ActorIndex >= 0; --ActorIndex) { AActor* Actor = Actors[ActorIndex]; if (Actor && Actor->CanBeInCluster()) { ClusterActors.Add(Actor); } else { ActorsForGC.Add(Actor); } }
UObject
所引用的其余UObject
?TArray<UObject*> CollectedReferences;
FReferenceFinder ObjectReferenceCollector(CollectedReferences);
ObjectReferenceCollector.FindReferences(Object);
一度看了看Reference是怎么跑起来的,后来发现大部分的从UClass派生出来的类会制定对应的ClassAddReferenceObjects
方法,这个方法用于制定该类会和哪些东西产生对应的引用……
1.什么样的对象能够被unreal engine管理和回收:
unreal engine定义的类中,只有UObject或者是UObject的派生类建立的对象,才能被unreal engine管理,用完后才能被unreal engine回收。其它类好比:UStructs,不具备这个特性。
2.UObject或者是UObject的派生类的实例,建立和销毁的方式:
1).AActor类或者AActor派生类,虽然也是UObject的派生类,但建立和销毁方式不一样于通常UObject的派生类:
AActor建立方式:
UWorld::SpawnActor() //此方法建立Actor实例后,UWorld会持有Actor实例的引用
AActor销毁的方式:
AActor::Destroy() //此方法会将Actor实例从关卡中删除,并将Actor实例标记为“待杀死”,而后会在下一次GC时删除
2).除AActor类或者AActor派生类之外的其它UObject或者是UObject的派生类:
UObject可经过以下4种方式建立:
NewObject<class>() NewNamedObject<class>() ConstructObject<class>() new
UObject销毁方式:
UObject::MarkPendingKill() //此方法执行后,全部指向此实例的指针将设置为NULL,并在下一次GC时删除
3.垃圾收集器如何管理UObject的实例
1).AActor类或者AActor派生类的实例被建立后,会自动存放在垃圾收集器的对象根集合中,不会被自动回收。
2).除AActor类或者AActor派生类之外的其它UObject或者是UObject的派生类的实例被建立后,会自动被回收,若是想不被GC回收,主要有以下几种方式:
2.1).建立的实例做为UObject的派生类的成员变量,而且被标记为UPROPERTY()
2.2).建立的实例存放在TArray中,TArray做为UObject的派生类的成员变量,而且被标记为UPROPERTY()
2.3).建立的实例存放在智能指针中。(此说法待验证)
2.4).经过UObject::AddToRoot(),设置RF_RootSet标志(可参考:UObject Instance Creation)。