Is this a garbage collection issue?

Hiya

I’m having a problem with a TArray of scene components getting wiped out after I remove an item from it.

So, given:


UPROPERTY() TArray <UMyComponent *> Components;

If I call:


Components.RemoveAt(0)

Everything gets messed up, pointers in the UMyComponent class get set to 0xddddddddddddd, etc. The members of the list still have the correct pointers but the objects they point to seem to be destroyed. But not immediately.

I’ve stepped over the removal process above and it’s fine for quite a while afterwards, so then I hit continue and the list is corrupted then. So I suspect garbage collection.

Is there anything else I might be missing that could be causing this?

Is your class derived from UObject?

If not, you need to add a GC reference manually



class FMyClass : public FGCObject {
	///...

	virtual void AddReferencedObjects(FReferenceCollector& Collector) override {
		for (UMyComponent* Comp : Components) {
			Collector.AddReferencedObject(Comp);
		}
	}

	///...
};



Aaah. Thank you! Yes it is.

I also tried adding my uobjects to the root, which also worked, but I think your method looks better.

Actually, I’m not sure how to implement that. My structure is I have a static TArray and the pointers to my UComponents are inside that. As long as they’re in the list I’d like to keep them from being collected. What’s calling AddReferencedObjects and how does it know what to call it on?

I forgot to mention that this is in the context of an editor plugin. Can I get away with just using AddToRoot() and RemoveFromRoot() when I remove an item from the list?

Edit: so the AddToRoot approach caused a new problem:


/Game/meshdupetest.meshdupetest still around trying to load ../../../../../../UnrealEngine/Projects/OctaneUE4Importer_411/Content/Maps/bakingdemomap.umap

   (Object is not currently rooted)

This only started happening after adding objects to the root.

I have an onleveldelete delegate that removes the components from the main list and removes them from root but it sounds like this isn’t enough. Is there an editor-level-change event?

The gc will automatically call the function before it collects. The engines editor code uses this method extensively as opposed to add to root. The advantage is you dont have to remove it from root when you are done. I use it for dungeon architect extensively.

I’ve also noticed that add to root invalidates your references when you save the level you are working on

Gotcha.

So I made a new class with a TArray that will register the members of that TArray. How do I let the framework know about the new object? Do I spawn it, or make it a UPROPERTY member of something else?


class FOctaneComponentCollection : public FGCObject{
    static TArray <UOctaneComponent *> Components;


    virtual void AddReferencedObjects(FReferenceCollector& Collector) override {
        for (UOctaneComponent * Component : FOctaneComponentCollection::Components) {
            Collector.AddReferencedObject(Component);
        }
    }
};

I guess an FGCObject can’t be created using NewObject and can’t be spawned, so would it need to be a member of a UObject?

Edit: okay, I read the docs and it’s for garbage collection on non-uobjects. I added it to my existing holder class and got rid of the code above as it was unnecessary. It seems to be working now! Thanks! :slight_smile:

Same problem, new scenario. I’m now experiencing unexpected garbage collection on an AActor child.

So I have AMyActor and inside it are some things like static mesh components, rendertarget cameras, etc. They have the UPROPERTY() macro and are initialized to nullptr in the header.

I call SpawnActor and then inside the actor constructor I make a bunch of NewObjects to populate these children.

However, some time after spawning I need to reference the mesh inside the actor and it’s set to some invalid garbage pointer such as 0x5d5d5d5d5d5d5d5d. Looks like garbage collection again to me. But I’m not sure why.

Adding this actor to root caused problems when I switch maps, so I took that out. But what do I need to do here? Everything is a UObject, so everything should be managed. How do I stop it from GCing stuff I’m using?

When creating objects inside of a constructor, try using CreateDefaultSubobject instead of NewObject.

Can’t that only be used once? I’m already using it to spawn another mesh inside of it.