I cant fully destroy actors after I spawn them! ActorIterator still finds them. What is Better Destroy Method?

#My Project on Drop Box
I’ve included lots of documentation on controls and such

NathanLyer/VictoryGameNov8

I provided a setup to easily test

-creating lots of static mesh actors, press F10, then press F2, then drag mouse around pressing CTRL + LMB to spawn objects

-deleting all the objects in world (SHIFT + T)

-in the console you can see the whole list that is being run through each time SHIFT + T is pressed, showing lots and lots of nones, uses the code I’ve posted, an Actor Iteratorloop


Dear Friends at Epic,

I’m sorta in shock at the moment and I been debugging this issue for four hours

so I may not be exactly coherent.

buut

It seems I cannot destroy actors I create, after I spawn them!

I am using the most rigorous destroying method I know of.

void AVictoryGamePlayerController::VDestroy(UObject * ToDestroy)
{
	if (!ToDestroy) return;
	if (!ToDestroy->IsValidLowLevel()) return;

    ClientMessage("DESTROY CALLED ON");
 ClientMessage(ToDestroy->GetName());

	//~~~~~~~~~~~~~~~~~~
	ToDestroy->ConditionalBeginDestroy();
	ToDestroy = NULL;
	
	//*** GC ***
	GetWorld()->ForceGarbageCollection(true); //full purge 
}

I am calling a full purge of the GC after each actor is destroyed!

Specifically, I am destryoing special versions of Static Mesh Actors using ActorIterator

//~~~ Victory Walls ~~~
	TActorIterator< AVictoryWall > ActorItrWalls(TheWorld);
	while(ActorItrWalls)
	{
		VDestroy( * ActorItrWalls);
		
		//~~~~~~~~~~
		++ActorItrWalls;
	}

#Is ActorIterator Keeping Them To Avoid Disturbing It’s Indicies?

I just thought of fact that maybe the actoriterator is preserving them somehow since iterating over a list of actors as they are being destroyed might be confusing to manage.


#Visually and Collision-Wise, the destroyed actors do disappear

The odd thing is

when I run my destroy function

visually, they disappear!

And their collision also goes away after a momentary pause (0.5-1.5 seconds or so)

But if I run my actor iterator over all versions of my static mesh actor present in the world, they are STILL in the world at their same locations

//~~~ Get Total Count ~~~
TActorIterator< AVictoryWall > ActorItrCtr(RV_World);
RV_Int32 = 0;
while(ActorItrCtr)
{
	//why getting duplicates after loading and then saving again?!?!!
	Optimize("Loaded DuplciatE?");
	Optimize(( * ActorItrCtr)->GetName());
	Optimize(( * ActorItrCtr)->GetActorLocation().ToString());
	RV_Int32++;
	++ActorItrCtr;
}
OptInt("Current Wall Count", RV_Int32);

When I run the above code after destroying them all, I get output showing them as still being at their locations, even tho they are no longer visible

#If I Call Destroy Twice, It says None…7 times (they’re still there)


#Proper Way to Destroy Actors During Runtime?

Is there a different series of functions I should be calling to destroy Actors spawned during runtime?


#Summary

I can spawn Static Mesh Actors during runtime

But I cannot delete them even with full purging calls to GC


#No UPROPERTY() References

There are no addtoRoots() or UPROPERTY() references to the created SMA’s, ever :wink:


#Stronger than Full Purge of GC?

Whatever ActorIterator is doing, shouldnt a full purge of the GC be more powerful?

Any help would be very much appreciated!

I thought the destroy function I created was as aggressive as I could possibly make it!

Looking forward to hearing from you!

Rama

#My Inconvenient Workaround

currently I am working around this by using

TActorIterator< AVictoryWall > ActorItr(RV_World);
	while(ActorItr)
{
	if (ActorItr->GetName() == "None") 
	{
		++ActorItr;
		continue;
	}
       //.... actual code for loop
}

but am I going to have to do this for the rest of my life?

its an extra bit of code to add to every single actor iterator loop

(even if I use forloop, while is just my stylistic choice)

How do you destroy stuff over at Epic?

Rama

#Is this a Memory Leak?

I created and destroyed about 200 objects

Every time I try to delete them, it runs through the full 200 or so via the actor iterator

I then left my game running for about 20 min

and ran the delete function again

All 200 were still there!!!

Is this a memory leak?

Rama

#Behavior is same with Object Iterator

I just checked and the behavior is exactly the same with Object Iterator, the objects do still appear to exist

soooo

how do I permanently get rid of them so I dont have to use the inconvenient work around?

:slight_smile:

Rama

Im curious did you try accessing any of these supposedly deleted actors from the list? Obviously the list would return a value but Im interested if the actual actor was still there in memory or if the reference was bad.

Hi there!

They were indeed accessible, I could call GetName() on them, even though it returned None :slight_smile:

deletedActor->GetName() //works

Okay I just wasnt sure because you compared it against none in the above code.

Finally!

I solved this problem using K2_DestroyActor()

:slight_smile:

Here’s my complete code for anyone’s use

void AVictoryGamePlayerController::VDestroy(UObject * ToDestroy)
{
	if (!ToDestroy) return;
	if (!ToDestroy->IsValidLowLevel()) return;
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	//Actor?
AActor * AnActor = Cast(ToDestroy);
if (AnActor)
{
	AnActor->K2_DestroyActor();
            ToDestroy = NULL;
}

//Object - BeginDestroy
else
{
		//Begin Destroy
		ToDestroy->ConditionalBeginDestroy();
		ToDestroy = NULL;
	}
	
	//GC
	GetWorld()->ForceGarbageCollection(true);
	
}

Hi Rama,

Have you checked to make sure you aren’t keeping a reference to the actor?

yes I am not keeping any references, I do not added the spawned meshes to any arrays and spawn many many of them, as I am building a world this way.

So I’m quite puzzled :slight_smile:

The fact is, they ARE disappearing and losing collision, but they just cannot be fully GC’ed no matter what I do :slight_smile:

Rama

The entire spawn code looks like this, very simple

AVictoryWall is a temp ptr ref and there’s no UPROPERTY() references, ever.

SpawnInfo = FActorSpawnParameters();
	SpawnInfo.bNoCollisionFail = true;
	SpawnInfo.Owner = VictoryPC;
	
	if (JoyType == JOYSPAWN_VICTORYWALL)
	{
		//No VictoryWall BP ?
		if (!VictoryPC->VictoryWallBP) return;
		//~~~~~~~~~~~~~~~~~~~~~
		
		//Spawn
		AVictoryWall* newWall = 
			GetWorld()->SpawnActor(
				VictoryPC->VictoryWallBP, GetActorLocation(), GetActorRotation(), SpawnInfo );

changing SpawnInfo.bNoCollisionFail to false did not change the behavior

Switching to using a non-globally-retained spawninfo did not change the behavior (created temp version inside function with same results)

#My Project on Drop Box
I’ve included lots of documentation on controls and such

NathanLyer/VictoryGameNov8

I provided a setup to easily test

-creating lots of static mesh actors, press F10, then press F2, then drag mouse around pressing CTRL + LMB to spawn objects

-deleting all the objects in world (SHIFT + T)

-in the console you can see the whole list that is being run through each time SHIFT + T is pressed, showing lots and lots of nones, uses the code I’ve posted, an Actor Iteratorloop

Any further assistance with or without checking out my project directly would really help, as I have no idea how to fix this issue

Thanks in advance!

:slight_smile:

Rama

#Tried Calling FinishDestroy

I tried calling ConditionalFinishDestroy a few moments after calling BeginDestroy, multiple times, but this did not stop ActorIterator from finding all the objects with name None still.

Please do help me figure out how to get actoriterator to not find these basically non-existent actors :slight_smile:

Rama

Just as a heads up @rama, this became very useful for me just now. Thanks for posting this!

(if I could produce repro steps and a bug report, I would, however in my test bed I don’t get this issue and my level designer does [RAM increasing over a number of games], using K2_DestroyActor instead of Destroy() works though… so… yay)