Forum rules - please read before posting.

Relatively easy GC Performance improvements ( -96% to 100% less GC per frame)

ChrisIceBox , I've been wondering for a while about the garbage collection data that Adventure Creator generates every frame.

I noticed for example this issue was important to find and act on:

Checking this simple checkbox to avoid unnecessary input definition checks every frame, is a huge improvement on mobile platforms, and may be easily missed.

The profiler says that after fixing this setting, AC still creates about 1.1Kb + 0.6kt of GC every frame, which is a lot. On 60FPS that would be around 6Mb of GC per minute. 

The profiler OnGUI.BeginGUI(), lists 1.1Kt on it's root level, and points to multiple child components, including 3 from AC: 


  • Had to break this in multiple parts because of character limits per post.

    I've previously debugged OnGUI() stuff on other assets, and it's a surprising fact that the existance of OnGUI() callback/method already creates a significant amount of GC per frame, even if has zero lines of code inside it. Also, the profiler doesn't bother to show this GC on the corresponding lines, but only at their parent OnGUI.BeginGUI(). 

    I needed to dig deeper, and started commenting out various parts of AC code to find what actually does what.

    Luckily I soon found out that I can ignore both of these:
    ..because MenuPreview can be disabled entirely in the GameEngine, and ActionListManager's OnGUI is wrapped in editor-only code, so it doesn't run on devices. 

    Still, commenting out  ActionListManager.OnGUI() AND StateHandler.OnGUI() removed the OnGUI.BeginGUI() from the list altogether, confirming that there were no other hidden OnGUI()-sources.

    StateHandler.OnGUI() naturally is entirely different, as it's an important part of the engine ... however I actually found out that it seems that in my case I could actually get rid of it without breaking my game! However, in this case I was actually creating a non-adventure game that just relied on AC because I love it. It only uses ActionLists, Events, Menus and Variables of AC - and probably localization in the future. 

    But I was surpised to find out everything seemed to work fine even with StateHandler.OnGUI() commented out. Now you might think that the title of this issue was just clickbait, and this information is useless to most AC projects, theres more.

    According to the profiler, there was about 0.7Kb of GC still generated by StateHandler.Update(). I dug a few levels deeper and found out that StateHandler.Update() called PlayerMenus.UpdateAllMenus()  and 100% of the GC was generated in on this line in :
    // else if (1 == 2 && menus[i].IsOff () && menuIdentifier == menus[i].id.ToString ())
  • Last part here, with the fix that should help everyone using AC.

    In other words, this tiny ToString() , used to compare looped menuIds created all this (0.7Kb) GC. It's rather simple to fix:  just save and use the string of the id as a separate value, idString (in Menu.cs).

    For example like this:
    /** A unique identifier */
    //public int id;
    /** Save Id separately as a string to avoid frame specific GC */
    public string idString;
    private int _id = 0;
    public int id{
    get {
    return _id;
    set {
    _id = value;
    idString = value.ToString();

    And then use the string value directly:
    // else if (1 == 2 && menus[i].IsOff () && menuIdentifier == menus[i].idString)

    There are many places where ToString() could be replaced, but just this one loop caused all the GC on every frame.

    After this, the profiler showed just 24B of GC every frame, and that seems to be from the profiler & editor itself, so it should be 0GC on the devices. 

    Also, I have about 8000 lines of custom code in this project with many coroutines, but I've managed to keep the coroutines GC free by using this asset:

  • edited February 2017
    Thank you for the detailed runthrough, @ilmari!

    ActionListManager's OnGUI function is also hidden behind a UNITY_EDITOR check, but the ToString() conversion is a valid point.  I shall look into this as part of AC's next update.
  • ChrisIceBox  I'm glad I could contribute something back.

    EDIT: I copypasted (1 == 2 &&) accidentally inside the code, it was just a way to temporarily disable it.

    I have a further suggestion also, and also a question: would you mind clarifying why StateHandler.OnGUI() exists and how crucial you consider the code to in OnGUI() instead of some other callback? Probably has something to do with the fact that its called twice per frame?

    I'm not sure if you like the idea, but I would love the ability to have the OnGUI() live in a separate class which could be turned on Off (and back on) via an AC setting or AC API call or something. That way it would be possible to reduce the GC overhead per frame to complete zero.
  • StateHandler's OnGUI function exists as a way of calling all OnGUI code from one place, so that there's only one such function being called when running builds.  The script does a similar thing with Update, LateUpdate and FixedUpdate.

    AC makes use of OnGUI for more things than just the menu system - camera borders, camera fading, cursor graphics, etc are done within it.  I'd say it's crucial for 99% of projects, but as it's used only for displaying purposes - and not input, gameplay etc - it could feasibly be removed if you don't make use of any of those features.  Perhaps it'd be possible to introduce some kind of preprocessor around it, so that you can add in e.g. "ACIgnoreOnGUI" to your Scripting Define Symbols box, and AC would bypass it.
  • edited February 2017
    I see, thanks for the clarification :)

    StateHandler.OnGUI() only seems to affect the AC-based menus, which is not a problem for me, as I use only UGUI menus, but still link them to the AC menu system. Seems to work just fine without the OnGUI. I believe that would lower the "99% of projects" to a smaller number, as more projects could do fine without those camera and cursor effects.

    I also believe doing this would be worth the effort when targeting mobile platforms, as that lone OnGUI() automatically generates 384b of GC per frame, which is about 0.6Mb - 1.3Mb per minute (30 or 60 FPS).

    "Perhaps it'd be possible to introduce some kind of preprocessor around it, so that you can add in e.g. "ACIgnoreOnGUI" to your Scripting Define Symbols box, and AC would bypass it."

    I would be quite happy with that solution! Anything like that works so I don't have to hack AC and can update it easily. I still have a suggestion if you implement "ACIgnoreOnGUI" : please consider adding a new public function to StateHandler, and move the contents of OnGUI() in there, and the run that function inside OnGUI.

    Something like:

            private void OnGUI ()


                RunOnGUI ();


            public void RunOnGUI ()


     OnGUI() contents here

                // ...  

    The benefit of that would be that if I (or anyone) still wants to activate the OnGUI (runtime), it's possible to do it in custom code. I'm thinking about 2 new classes: one to activate/disable the other script whenever any other script (or ActionList) sends an event that we want to enable OnGUI. The other script then simply consists of OnGUI() which runs the public function in StateHander.

    It should then be easy to activate/disable the OnGUI with an ActionList, so that I could enable the stuff just for some camera effects temporarily.

    If other people would be interested in this optimization, I could share some code also (assuming I need it myself).
  • Yes, that's a fair request.  Consider that, plus the optimisation in the first post, included in v1.56.
  • Awesome, thanks :)
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.