您的位置:首页 > 产品设计 > UI/UE

Unreal Engine 4 —— UE4的内存模型杂七杂八

2017-08-03 17:31 1476 查看
这篇博客介绍了UE4的内存模型相关的东西与我在运用UE4时相关的一些心得。

由于整个内存模型比较复杂,因此这篇博客的点可能会比较散乱……可能日后会进行整理(也可能不会)

UObject
FUObjectItem

UE4运行的基本单位是
UObjet
,然而
UObject
针对于内存相关的东西都储存在结构体
FUObjectItem
中。有个全局变量
GUObjectArray
,可以通过以下代码来遍历所有的Objects:

for (FRawObjectIterator It(false); It; ++It)
{
FUObjectItem* ObjectItem = *It;
UObject* obj = ObjectItem->Object;
}


可以通过如下代码来获得一个
UObject
对应的
ObjectItem


FUObjectItem* ObjectItem = GUObjectArray.ObjectToObjectItem(Object);


GUObjectArray
中有几个函数可以通过索引和ObjectItem、Object的相互获取,对应的函数为
IndexToObject
ObjectToIndex
IndexToObjectUnsafeForGC
等。

GUObjectArray
中所有的
UObjectArray
的分布是有顺序的——那些不会被GC的
UObject
,例如各StaticClass、核心Object,GamePlayInstance等会放在前面;而那些有可能被GC的
UObject
,则放在后面。此外,
GUObjectArray
中有个变量
ObjLastNonGCIndex
,用于分隔这两类
UObject


/**
* 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


每一个
FUObjectItem
里面有一个变量
ClusterRootIndex
,这个储存的是当前Object所在的Cluster的root object所在
GUObjectArray
的索引。

// UObjectArray.h
// UObject Owner Cluster Index
int32 ClusterRootIndex;


引擎中有一个全局变量
FUObjectClusterContainer GUObjectClusters
,用于管理内存中所有的Clusters。

// Get the number of all clusters that have been allocated.
GUObjectClusters.GetNumAllocatedClusters()


但很奇怪的,在我新建的若干个测试关卡/项目中,这个值一直为0……

一个关卡
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
方法,这个方法用于制定该类会和哪些东西产生对应的引用……

<未完待续>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unreal engine ue4 内存