轉自: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)。