4.7.6 Garbage Collector bug

How to reproduce:

  1. Create a new c++ project, Basic code (i called it GarbageCollectorTest).
  2. Create a new GameState based class (called it MyGameState)
  3. Create a new UObject based class (called it MyObject)
  4. Modify the code as below
  5. Compile as Development Editor, set the game mode as GarbageCollectorTestGameMode
  6. Run it, open the console, and use the command TestMyObject

Code:
MyGameState.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/GameState.h"
#include "MyGameState.generated.h"

/**
 * 
 */
UCLASS()
class GARBAGECOLLECTORTEST_API AMyGameState : public AGameState
{
	GENERATED_BODY()
public:
	UFUNCTION(Exec)
	void TestMyObject();
	
protected:
#if !UE_BUILD_SHIPPING
	UPROPERTY()
	class UMyObject* MyObject;
#endif	
	
};

MyGameState.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "GarbageCollectorTest.h"
#include "MyGameState.h"
#include "MyObject.h"



void AMyGameState::TestMyObject()
{
#if !UE_BUILD_SHIPPING
	MyObject = NewObject<UMyObject>(this, UMyObject::StaticClass());
	UE_LOG(LogTemp, Error, TEXT("MyObject created: %s"), (MyObject != nullptr) ? TEXT("TRUE") : TEXT("FALSE"));
#endif
}

MyObject.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Object.h"
#include "MyObject.generated.h"

/**
 * 
 */
UCLASS()
class GARBAGECOLLECTORTEST_API UMyObject : public UObject
{
	GENERATED_BODY()
	
	virtual void BeginDestroy() override;
	
	
};

MyObject.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "GarbageCollectorTest.h"
#include "MyObject.h"


void UMyObject::BeginDestroy()
{
	Super::BeginDestroy();
	UE_LOG(LogTemp, Error, TEXT("MyObject destroyed"));
}

GarbageCollectorTestGameMode.h

// Copyright 2015 DESTINYbit. All Rights Reserved.

#pragma once

#include "GameFramework/GameMode.h"
#include "GarbageCollectorTestGameMode.generated.h"

/**
 * 
 */
UCLASS()
class GARBAGECOLLECTORTEST_API AGarbageCollectorTestGameMode : public AGameMode
{
	GENERATED_BODY()
	
public:
	AGarbageCollectorTestGameMode(const FObjectInitializer& ObjectInitializer);
	
};

GarbageCollectorTestGameMode.cpp

// Copyright 2015 DESTINYbit. All Rights Reserved.

#include "GarbageCollectorTest.h"
#include "GarbageCollectorTestGameMode.h"
#include "MyGameState.h"


AGarbageCollectorTestGameMode::AGarbageCollectorTestGameMode(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	GameStateClass = AMyGameState::StaticClass();
}

Resulting behaviour:

MyObject gets garbage collected after some random time, as we can see in the log:

[2015.05.03-17.42.39:499][383]PIE: Info Play in editor start time for /Temp/UEDPIE_0_Untitled_1 -0.239
[2015.05.03-17.42.42:434][732]Cmd: TestMyObject
[2015.05.03-17.42.42:434][732]LogTemp:Error: MyObject created: TRUE
[2015.05.03-17.43.39:438][495]LogTemp:Error: MyObject destroyed

The object will not be GC’ed, correctly, if we remove the “#if !UE_BUILD_SHIPPING” from the UPROPERTY declaration.

Expected behaviour:
MyObject should not be GCed until we set the pointer to NULL.

This is not a critical issue, i encountered it while working on some debug code, but it is strange.

Hope this helps,
Simone Daminato.

For a quick debug, here’s the source code.

source code files

Hey

It sounds as though you’re seeing the object getting destroyed/GC’d without the destroy function being called, is my understanding correct? Using the code you provided I’m seeing the opposite behavior. With the “#if !UE_BUILD_SHIPPING” block the object is created when I call the function and is destroyed roughly a minute later. Not using the if block however will create the object which stays around until the PIE session is exited. Let me know if I’m misinterpreting something or if you’re seeing different behavior.

Cheers

You’re right .
More exactly, the destroy function is called, but it shouldn’t be destroyed at all.

My point is: since i have a uproperty pointing to it, it shouldn’t be destroyed.

Hey

Sorry for the delayed response. You’re correct that the object should not be destroyed since the destructor is not being called anywhere. This behavior has been bugged (UE-15938) for investigation.

Cheers