Search Unity

Animation events cause gc allocation?

Discussion in 'Scripting' started by cometeor, Oct 17, 2018.

  1. cometeor

    cometeor

    Joined:
    May 20, 2011
    Posts:
    64
    0501497C-2B8A-49fc-B820-B6BF55D03B60.png I profiled my project and found gc allocation in Animator.FireAnimationEvents, even my event callback does nothing.
    ADE3F463-10D7-4789-BFA6-89190655B90E.png
    Any workaround? Is this situation occurred on mobile platform?
     
  2. cometeor

    cometeor

    Joined:
    May 20, 2011
    Posts:
    64
    And my unity version is 2017.2
     
  3. cometeor

    cometeor

    Joined:
    May 20, 2011
    Posts:
    64
    My bad. That's a test sample, but in my project i deleted the implementation of my function, still like this: B25295C1-A39F-43cc-A6D0-CCA7765EF5C1.jpg CEC1D292-6E06-409e-9D85-C6A8515A7477.jpg
     
  4. cometeor

    cometeor

    Joined:
    May 20, 2011
    Posts:
    64
    But after I deleted Debug.Log, the test sample didn't show any gc allocation anymore... the problem still exists in my project.
     
  5. 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).
    https://jacksondunstan.com/articles/3335
     
    Last edited by a moderator: Oct 17, 2018
  6. cometeor

    cometeor

    Joined:
    May 20, 2011
    Posts:
    64
    Ok, thanks. But how to make footstep sound consistent with footstep animation without events?
     
  7. cometeor

    cometeor

    Joined:
    May 20, 2011
    Posts:
    64
    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.
     
  8. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    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.
     
    cometeor likes this.
  9. MartyMcFly

    MartyMcFly

    Joined:
    May 2, 2013
    Posts:
    17
    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:

    Code (CSharp):
    1. public class AnimationMessageSenderComponent : MonoBehaviour
    2.     {      
    3.         public string[] MessagesToSend;
    4.  
    5.         private int[] messageHashes;
    6.  
    7.         private void Awake()
    8.         {
    9.             HashMessageStrings();
    10.         }
    11.  
    12.         private void OnValidate()
    13.         {
    14.             HashMessageStrings();
    15.         }
    16.  
    17.         private void HashMessageStrings()
    18.         {
    19.             messageHashes = new int[MessagesToSend.Length];
    20.  
    21.             for (int i=0; i< MessagesToSend.Length; i++)
    22.             {
    23.                 messageHashes[i] = Animator.StringToHash(MessagesToSend[i]);  
    24.             }
    25.         }
    26.  
    27.         public void SendAnimationMessageByIndex(int index)
    28.         {
    29.             if (index > messageHashes.Length - 1)
    30.             {
    31.                 Debug.LogError("Can't send animation message from " + this.gameObject.name + ". Given index exceeds message list length.");
    32.             }
    33.             else
    34.             {
    35.                 // Do stuff.
    36.                 // e.g. Forward message to some global messaging system, where message receivers can register
    37.                 AnimationMessage.Post(messageHashes[index]);
    38.             }
    39.         }
    40.     }
     
    Gucci10C and buc like this.