Animation events cause gc allocation?

I profiled my project and found gc allocation in Animator.FireAnimationEvents, even my event callback does nothing.

Any workaround? Is this situation occurred on mobile platform?

And my unity version is 2017.2

“A call to Debug.Log() creates and disposes of at least one string, so if our game contains many of these calls, the garbage can add up.”

Do not use Debug.Log for performance optimization purposes. It’s only okay for logging or for checking purposes (if your code executes somewhere or not).

My bad. That’s a test sample, but in my project i deleted the implementation of my function, still like this:

But after I deleted Debug.Log, the test sample didn’t show any gc allocation anymore… the problem still exists in my project.

No matter what, both the C# and Unity events are allocating some small amount of memory. This is why I usually don’t recommend to use events in the hot path. But using sparingly is okay (once in a while animation send an event call to do something is okay, sending footsteps event, which occurs frequently is not okay IMHO, unless you can handle the Garbage collection).

Ok, thanks. But how to make footstep sound consistent with footstep animation without events?

I found some related things which cause this problem: string arguments and how many times Animator.FireAnimationEvents are called. It seems when event fired everytime, it allocates several bytes depends on string argument length.

Best solution I’ve found is to use curves baked in the animation.
That way you can poll animator for the parameters value that is returned by the current frame. (Animator.GetFloat(…));
Then, evaluate if the footstep sound should be played, based on the value.

Alternative is simply fake it using AnimationCurve values. Although, not that accurate and will require a lot of value tweaks if used in fast iteration / with lots of animations.

1 Like

Exactly. My profiler also tells me the GC allocs are only caused by string allocs.
For strings you’d always expect that. But there don’t seem to be GC allocs caused just by the animation messaging system itself.

So what can you do?
Avoid string parameters.

Put a parameter list in the component itself and turn them into hashes.
Instead of sending (and creating) a string each time you send an index to a list of message strings.
As you have to do some comparison later and don’t want to create a string there either I’m turning all strings into hashes.

Untested in productivity:

public class AnimationMessageSenderComponent : MonoBehaviour
    {       
        public string[] MessagesToSend;

        private int[] messageHashes;

        private void Awake()
        {
            HashMessageStrings();
        }

        private void OnValidate()
        {
            HashMessageStrings();
        }

        private void HashMessageStrings()
        {
            messageHashes = new int[MessagesToSend.Length];

            for (int i=0; i< MessagesToSend.Length; i++)
            {
                messageHashes[i] = Animator.StringToHash(MessagesToSend[i]);   
            }
        }

        public void SendAnimationMessageByIndex(int index)
        {
            if (index > messageHashes.Length - 1)
            {
                Debug.LogError("Can't send animation message from " + this.gameObject.name + ". Given index exceeds message list length.");
            }
            else
            {
                // Do stuff.
                // e.g. Forward message to some global messaging system, where message receivers can register
                AnimationMessage.Post(messageHashes[index]);
            }
        }
    }
2 Likes