Wait for seconds/Coroutines, Garbage Collection and Performance

Hello guys! :slight_smile: I’d like to start out by saying I’m not the greatest programmer :sweat_smile:- I’m an artist but I get by enough. :roll_eyes: I am trying to combat a lot of GC and performance during functions that I call that do something over a specific time frame (a sword swing that happens in 1 second, for example).

The problem is a lot of GC gets collected over the wait for seconds call, I’m not familiar with the coroutine method and wish to know the most optimized way to structure a simple function that does something over time (like attack)

My method is simply:

function Attack(){
     var time: float = 0;
     animation.Play();
     while (time < 1){ //or yield WaitForSeconds(1);
          time += Time.deltaTime;
          transform.lookat(enemy);
          yield;
     }
     doDamage(10);
}

http://postimg.org/image/mabt1p3eb/

Thanks for any insight and help on the topic guys!! :smile::sunglasses::wink:

uhhhh, that says 96 bytes…

Just so you understand, a coroutine is an object, so when you start one… you’ll have to allocate memory. It’s just a given. You can’t avoid that.

Your image you post… has very little memory allocation.

The whole coroutine uses 0.7kb though (highlighted in red)- I’m more concerned that the total cpu usage of the function alone is 20% which seems like a lot, wouldn’t that be considered high? I feel like my method is primitive and can be improved on its performance

Cache your yield before and use waitforseconds(0). WaitForEndOfFrame or WaitForFixedUpdate allocate memory.

var yieldNone = new WaitForSeconds(0);

while (time < 1)
{
time += Time.deltaTime
transform.lookat(enemy)
yield return yieldNone;
}

So in this you have to pre-define however long you want to wait from “yieldNone”, but doesn’t “while(time <1)” still force to wait 1 second?

I think you might be mistaken by what that 20% represents.

It’s not 20% of total CPU usage. It’s 20% of the processing cycle of the game. 20% of what is actually going on is that… if you had more going on, it’d be less, because more things would be taking up stuff.

It’d be like if you had to clean your room, and your room had to have its bed made, the clothes put away, and the floor vaccuumed. The bed making is 33% of the workload. Where as if you added more to the workload, say organize a bookshelf, and dust everything. Now making the bed is 20% of the workload.

You could then compare that to the actual system usage (look in task manager for that), the coroutines activity would be 20% of the overall system usage, which is probably puttering along at some small percentage of total system capacity.

As for the caching, this is useful if you were using a yield instruction like WaitForSeconds. But in your code above you use no yield instructions, you just yield nothing.

And if you want to yield for 0 seconds, like brianasu is showing… yield null. Why even allocate a yield instruction for that? Yielding WaitForSeconds(0) waits 1 frame, which yield null does as well.

1 Like

yield null gets boxed and causes Garbage :slight_smile:

just do a yield with your cached value of 1 second. I thought you wanted to do something int the loop that is why I did the yield 0 seconds.

just make the yield a member of your class.

private WaitForSeconds myYield = new WaitForSeconds(1.0f); and reuse it.

No it doesn’t… null can’t be boxed.

It’s literally an empty pointer to an object. How would that get boxed?

Also, they’re not yielding a WaitForSeconds, they’re using a while loop to wait 1 second. They could move to using a WaitForSeconds, in which case they should cache the yield instruction, but as it stands… that while loop uses no garbage. Actually, it’d use less than the WaitForSeconds option since the WaitForSeconds would result in needing to create that object.

As it stands, their ‘Attack’ method is as performant memory wise as it can be. Hence the minimal amount of garbage it has… which is unavoidable. A coroutine is going to create some garbage no matter what, since the coroutine itself is an object!

That is of course barring any garbage created in ‘doDamage’.

Either way though, this is such a poster child case of premature optimization, I sincerely would like to impress upon OP that it’s not a huge concern. I believe they’re misunderstanding what those numbers in the profiler mean, hence my previous post about what that 20% actually represents.

calm down mate… i made a mistake i was thinking of yield return 0…

:eyes:

You literally have no idea the state of my mood as this medium is text only. So that statement only serves to condescend.

If I had used name calling, or the sort, only then could I agree you could discern if I’m worked up, and need to calm down.

Hmm, I see what you’re saying here. I’m glad to hear that is the most optimal method of an attack cycle function (as I’ve already implemented in several places). I see now what that 20% represents- being an optimized freak early on I like to keep things clean and orderly before it gets out of hand, I know GC is one of those things.

Thanks for your insight on the subject! :smile: