UE4的內存模型

轉自:https://blog.csdn.net/noahzuo/article/details/73565259數組

UObjectFUObjectItem

UE4運行的基本單位是UObjet,然而UObject針對於內存相關的東西都儲存在結構體FUObjectItem中。有個全局變量GUObjectArray,能夠經過如下代碼來遍歷全部的Objects:函數

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

能夠經過以下代碼來得到一個UObject對應的ObjectItempost

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方法,這個方法用於制定該類會和哪些東西產生對應的引用……

 

不受內存管理的內存

    • malloc & free
    • new & delete
      new與malloc的區別在於,new在分配內存完成以後會調用構造函數。

內存管理的內存

  • 對於不是繼承自UObject的Native C++類,使用TSharedPtr、TAutoPtr、TWeakPtr、TSharedRef、TScopedPointer管理
  • 對於繼承自UObject的子類
    建立: UObject::NewObject<> 或是 UObject::ConstructObject<>,其中ConstructObject能夠作更復雜的參數配置
    銷燬:當計數爲0時,自動釋放;調用UObject::ConditionalBeginDestroy()手動釋放。若要強制調用垃圾回收,則調用UWorld::ForceGarbageCollection(true)。
  • 對於繼承自AActor的子類
    建立: UWorld::SpawnActor<>
    銷燬: AActor::Destroy()
  • TArray<>數組須要用UPROPERTY()修飾,不然會致使內存管理錯誤
  • 繼承自UActorComponent的組件,使用AActor::CreateDefaultSubobject<>,一樣組件的指針變量也須要用UPROPERTY()修飾。

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)。

相關文章
相關標籤/搜索