When does instances get garbage collected ?

I have a simple code snippet that runs on tick

On the first tick i create a scene component that i have derived into my own class UCSWSceneComponent

I have a UPROPERTY() declaration in a parent scene component

UPROPERTY(Transient, VisibleAnywhere, Category = "CSW");
TObjectPtr<UCSWSceneComponent> trans;

I have a counter so the first tick i call

trans = NewObject<UCSWSceneComponent>(this,TEXT("Test"));

trans->RegisterComponent();

trans->AttachToComponent(this, FAttachmentTransformRules::KeepRelativeTransform);

and when tick has run for 1000 times i call

trans->DestroyComponent();		

trans = nullptr;

But the code never gets deallocated. Either in play mode or in editor mode ?
When will it be GCed ?

Assuming you meant the object, it will. How are you testing this? Logging in destructor?

Typically, sometime within 1 minute.

I can see that my test code wasnt exact. I added a sub component (USceneComponent) to trans instance component before i called DestroyComponent. If i dont add this component it will be GCed but when i add the sub component, the sub component is transfered to the parent of the trans component but trans will never be GCed even if it is marked for GC

You could invoke garbage collection manually via

GEngine->ForceGarbageCollection(true);

Interesting.

I threw together a quick test to try to reproduce, but everything worked as expected (in 5.4.4):

[2024.12.03-16.19.43:083][589]LogTemp: Creating TestSceneComponent
[2024.12.03-16.19.43:083][589]LogTemp: TestSceneComponent Constructed
[2024.12.03-16.19.43:083][589]LogTemp: TestChildSceneComponent parent is now TestSceneComponent (was null)
[2024.12.03-16.19.45:691][738]LogTemp: Destroying TestSceneComponent
[2024.12.03-16.19.45:692][738]LogTemp: TestChildSceneComponent parent is now RootComponent (was TestSceneComponent)
[2024.12.03-16.20.32:091][296]LogTemp: TestSceneComponent Destructed

What version are you using?
Not sure how different out setups are, this is the actor code I was using:

ATestActor::ATestActor() : TestComponent(nullptr), TickCounter(0)
{
 	PrimaryActorTick.bCanEverTick = true;
	USceneComponent *RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
	SetRootComponent(RootComponent);
}

void ATestActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	++TickCounter;
	if (TickCounter == 1) {
		UE_LOG(LogTemp, Log, TEXT("Creating TestSceneComponent"));
		TestComponent = NewObject<UTestSceneComponent>(this, TEXT("TestSceneComponent"));
		TestComponent->RegisterComponent();
		TestComponent->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
		UTestChildSceneComponent *TestChildComponent = NewObject<UTestChildSceneComponent>(this, TEXT("TestChildSceneComponent"));
		TestChildComponent->RegisterComponent();
		TestChildComponent->AttachToComponent(TestComponent, FAttachmentTransformRules::KeepRelativeTransform);
	} else if (TickCounter == 150) {
		UE_LOG(LogTemp, Log, TEXT("Destroying TestSceneComponent"));
		TestComponent->DestroyComponent();
		TestComponent = nullptr;
	}
}

TestSceneComponent just logs in ctor/dtor.
TestChildSceneComponent just constantly checks it parent and logs changes.

I do the same in principal but i do tick an actor from the editor as well

Version 5.5.0

You can find my project at

wich is a project in work. You can see the problem when unloading/loading maps by changing the map urls between a valid map and an empty string. Map is provided in project under /maps