Download

Memory not being cleared when editor only actor deleted.

Hi guys,

Does anyone know why when creating an actor with the following test code, the memory starts at 600mb in the editor, then shoots up to 3000mb but when the actor is deleted it only goes down to 1800mb? I would have expected all of the memory to be returned so that we end up with 600mb again :confused:

MyActor.h



USTRUCT()
struct FMyStruct
{
GENERATED_USTRUCT_BODY()

UPROPERTY()
TArray<float> MyArray;

FMyStruct()
{

}

~FMyStruct()
{
MyArray.Empty();
}
};

UCLASS()
class TESTPROJECT1_API AMyActor : public AActor
{
GENERATED_BODY()

public:
// Sets default values for this actor's properties
AMyActor();
~AMyActor();

protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
virtual void BeginDestroy() override;

void OnConstruction(const FTransform& Transform) override;

public:
// Called every frame
virtual void Tick(float DeltaTime) override;

private:

TArray<FMyStruct> MyStructArray;

void MyFunc(TArray<FMyStruct>& MyArrayRef);
};


MyActor.cpp



AMyActor::AMyActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;

bIsEditorOnlyActor = true;

#if WITH_EDITOR
bRunConstructionScriptOnDrag = false;
#endif
}

AMyActor::~AMyActor()
{
MyStructArray.Empty();
}

// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
Super::BeginPlay();
}

void AMyActor::MyFunc(TArray<FMyStruct>& MyArrayRef)
{
for (int32 Index = 0; Index < 10000000; Index++)
{
FMyStruct MyStruct;

for (int32 Index2 = 0; Index2 < 10; Index2++)
{
MyStruct.MyArray.Add(1.f);
}

MyArrayRef.Add(MyStruct);
}
}

void AMyActor::OnConstruction(const FTransform& Transform)
{
MyFunc(MyStructArray);
}

void AMyActor::BeginDestroy()
{
Super::BeginDestroy();
}

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}


My thinking is that the destructor of the actor is emptying the MyStructArray and in turn that is then calling the destructor of the struct which is itself emptying its own MyArray of floats. This does not seem to be the case though as the memory is not being entirely returned.

Thanks in advance.

This is strange…

So the OnConstruction() function gets run twice when the actor is dragged into a level. Once for the preview actor and once for the real actor.

I had to add:



if (!IsTemplate(RF_Transient))
{
MyFunc(MyStructArray);
}


This then only runs MyFunc on the real actors OnConstruction(). This causes the ram to use only half of what it was using because the preview OnConstruction is not running.

Second problem (RAM not freed):

In the destructor of the actor the MyStructArray variable which is a TArray of FMyStruct is stating that the array is empty even though the for…loop is running correctly to add the data and the RAM is being used by the actor. This RAM is then never freed when the actor is deleted.

If I add UPROPERTY() to the


TArray<FMyStruct> MyStructArray;

then the memory consumption actually goes up when you delete the actor and the existing memory is never freed.

Please, can anyone help?

I think the memory is not freed because it remains as part of “undo” at editor, meaning that while there are steps able to be undone, those memory won’t be freed. When the map is saved, no undo are available, so you will see that memory will be freed again.

You are correct for the rise in memory when the TArray<FMyStruct> is marked with UPROPERTY(). It causes the rise in memory because of the undo cache being saved. Saving the map then reduces the memory as the undo cache is cleared. But the existing memory used by the actor is then also never freed, only the undo cache is freed.

The UPROPERTY also seems to slow the editor down.

If I do not use the UPROPERTY macro then the memory rises when dragging in the actor but is then never freed again when the actor is deleted. The MyStructArray says it is empty when being told to Empty() in the actors destructor. But the RAM/memory is still in use and is still never freed no matter the length of time since deleting the actor.

My question would be: Why is the actor quite clearly using RAM but yet the MyStructArray reports itself as being empty when the actors destructor is run?