Possible GC Issue?

Output Log:

Ensure condition failed: (Object == nullptr) || Object->IsValidLowLevelFast() [File:D:\UnrealEngine_4.12.5\Engine\Source\Runtime\Engine\Private\BlueprintGeneratedClass.cpp] [Line: 1036] 
Invalid object referenced by the PersistentFrame: 0x000000a3acc93400 (Blueprint object: DC_AIController_Dwarf_C /Game/Maps/UEDPIE_0_PlayMap.PlayMap:PersistentLevel.DC_AIController_Dwarf_C_65, ReferencingProperty: ObjectProperty /Game/Blueprints/Pawns/AI/Controllers/DC_AIController.DC_AIController_C:ExecuteUbergraph_DC_AIController.CallFunc_SpawnObject_ReturnValue) - If you have a reliable repro for this, please contact the development team with it.

Call Stack:

>	UE4Editor-Engine.dll!FPersistentFrameCollectorArchive::operator<<(UObject * & Object) Line 1032	C++
 	UE4Editor-CoreUObject.dll!UObjectProperty::SerializeItem(FArchive & Ar, void * Value, const void * Defaults) Line 34	C++
 	UE4Editor-CoreUObject.dll!UStruct::SerializeBin(FArchive & Ar, void * Data) Line 795	C++
 	UE4Editor-Engine.dll!UBlueprintGeneratedClass::AddReferencedObjectsInUbergraphFrame(UObject * InThis, FReferenceCollector & Collector) Line 1072	C++
 	UE4Editor-CoreUObject.dll!TFastReferenceCollector<FGCReferenceProcessor,FGCCollector,FGCArrayPool,0>::ProcessObjectArray(TArray<UObject *,FDefaultAllocator> & InObjectsToSerializeArray, TRefCountPtr<FGraphEvent> & MyCompletionGraphEvent) Line 352	C++
 	UE4Editor-CoreUObject.dll!TGraphTask<TFastReferenceCollector<FGCReferenceProcessor,FGCCollector,FGCArrayPool,0>::FCollectorTask>::ExecuteTask(TArray<FBaseGraphTask *,FDefaultAllocator> & NewTasks, ENamedThreads::Type CurrentThread) Line 999	C++
 	UE4Editor-Core.dll!FTaskThreadAnyThread::ProcessTasks() Line 1255	C++
 	UE4Editor-Core.dll!FTaskThreadAnyThread::ProcessTasksUntilQuit(int QueueIndex) Line 1149	C++
 	UE4Editor-Core.dll!FTaskThreadBase::Run() Line 621	C++
 	UE4Editor-Core.dll!FRunnableThreadWin::Run() Line 74	C++
 	UE4Editor-Core.dll!FRunnableThreadWin::GuardedRun() Line 23	C++
 	[External Code]	

I’m seeing things like FGCCollector, and gathering references. And it runs on the TaskGraph system.

My issue I’m having is this. I’m working with UObjects for a Task system I’m working on, so I’m spawning them, destroying them, etc. Anyway, once in a while, normally within a minute or two of PIE, I get the above issues that points toward GC. The node it’s complaining about appears to be a SpawnObject node and its ReturnValue pin.

In BP, it is really simple. I’m just Spawning a UObject, casting it, and setting it to a WeakObjectPtr that’s defined in C++.

For some reason (even when the game is paused, iirc) it will crash with this error I’m not sure what it is. I really don’t know if it is me, or if it is some GC bug.

As far as I’m aware, raw UPROPERTY ptrs work for AActor*, and TWeakObjectPtr works for UObject. Other than that, I am fairly new to GC and GC issues.

Thoughts?

Hey Krillin6,

This issue has been logged before but is marked as closed. Because of this, I need to replicate the issue to re-enter it.

  • In which way are you spawning the UObject (I am assuming you have your own BlueprintCallable function).
  • Can you post how you are defining the WeakObjectPtr in C++?
  • As well as what Blueprint class you are using the SpawnObject in, with if it is inherited from a C++ class or if it is a Blueprint Class.
  • Plus any other information you can post that would help me reproduce the issue.

Thanks.

So, here is the Construction.

It is in BP, via a BlueprintImplementableEvent in the AIController. I set the Outer to Self. I figured that would be safe. Don’t see why not. CurrentTask is the WeakPtr.

Here is the code for the WeakPtr variable:

UPROPERTY(SaveGame, BlueprintReadWrite, VisibleAnywhere, Category = "DC|Tasks")
	TWeakObjectPtr<UDC_TaskBase> CurrentTask;

I did just have another thought on how to properly “delete” or destroy UObjects. It totally slipped my mind last night.

Once the Task object is complete, it deletes itself, by calling ‘delete this;’ instead of something like ‘this->ConditionalBeginDestroy();’ The way it works now, the destructor is called via delete, which I use to do the cleanup of the sub-UOjects, which seems to work very well. For those, I am using ConditionalBeginDestroy().

Given my lack of experience, could this be the issue? I understand GC on one level, but then there are always those little improper things one can do, out of habit on suicidal classes in C++ that might be biting me in the butt within UE4 C++.

I will give that little change a go, and see if it makes any difference.

Edit: This is going to take a while, as my computer updated last night and restarted with VS open. It decided to not save my Build Configuration, and I now need to do a complete engine rebuild. :frowning: I’ll keep you posted.

I added and edited a comment earlier today. Now I’m checking back and it apparently didn’t work. :frowning:

Here we go again.

First, here is the information you asked for:

I’m currently constructing the UObject in BP, using a BlueprintImplementableEvent. It is then a simple cast to the WeakObjPtr variable.

UPROPERTY(SaveGame, BlueprintReadWrite, VisibleAnywhere, Category = "DC|Tasks")
	TWeakObjectPtr<UDC_TaskBase> CurrentTask;

Hopefully I’m at least doing that part correct.

Beyond that, I realized I was having the UObject Suicide with the delete command, so the Destructor would immediately fire off and run the cleanup of the SubUObjects, etc.

I realized I was using ConditionalBeginDestroy() on the SubUObjects, and they were not throwing any errors.

I have now changed the way the Top Outer UObjects are “destroyed” via ConditionalBeginDestroy(), and they at least don’t seem to crash, but the destructors take a long time to kick off, which isn’t Ideal, but it appears to work. Preferably, given the amount of these things I’ll be needing to create and destroy, I would love for them to go away more quickly, and not trip up the GC.

Are we not allowed to delete this; on UObjects? If not, is there a way to essentially destroy/delete them quickly? Perhaps this->FinishDestroy(); would work? In the meantime, I’ll do a little more testing and try to come to a conclusion. Once I figure this out, I will likely make an article on the Wiki for future devs.

Update:

ConditionalBeginDestroy(); is apparently the best way to trigger destruction, as far as I can tell, but the Destructor doesn’t get called until the GC does a run and “finishes it off.” At least, that’s what I’m going with.

So, what I’ve done so far is to dump using the Destructor code, and instead simply call all cleanup right before this->ConditionalBeginDestroy();

Also, since I don’t want GC to destroy the UObject early, the WeakPtr is now a regular UPROPERTY pointer. I’ve come to understand a little better what to do. There are some things that get obscured by all of the Destruction mechanics, I feel. I was expecting the object to get deleted upon “Destruction”, but it doesn’t, at least not right away.

I also for some odd reason I understood WeakPointers backwards. I misunderstood 's documentation, most likely. I’ll read it again, and attempt to clarify it on the Wiki if it wasn’t “just me.”

I believe that might be the best I have. If there is something I’m missing, let me know, but I think I was improperly using delete, at least according to other postings I’ve found now that I know what to look for.

On the plus side, the crashes appear to have subsided, so I think I got this.