Garbage collector spikes because of GUI

Our application seems to be suffering from serious garbage collector spikes in the profiler every few frames. The spikes are definitely being caused by OnGUI functions.

As long as there is a single OnGUI overload in the scene, the spikes will appear. They will drop the fps sometimes by 90% for a single frame. There’s no noticeable difference if there is something inside the OnGUI method, or if it’s empty. As long as it’s there the spikes happen.

Adding more scripts with overloaded OnGUI will cause spikes to happen more often.

Most of the time spent during those spikes are GC.Collect calls (generally from GUI.Repaint->BeginGUI).

This happens with both Unity 2 or 3.

Simple experiment
Scene with 1 cube and 1 camera, with the following script attached to the cube GameObject:

using UnityEngine;
using System.Collections;

public class OnGUITest : MonoBehaviour {

	// Use this for initialization
	void Start () {
	}
	
	// Update is called once per frame
	void Update () {
	}

    void OnGUI()
    {
    }
}

Profiler result:

Now lets try that same scene, but with the OnGUI function commented out:

using UnityEngine;
using System.Collections;

public class OnGUITest : MonoBehaviour {

	// Use this for initialization
	void Start () {
	}
	
	// Update is called once per frame
	void Update () {
	}

    //void OnGUI()
    //{
    //}
}

Profiler result:

You can see how this can cause a lot of problems in a larger scene where we try to maintain an fps of 60, but the spikes happen every few frames and lower it to 15-20, which is very noticeable. (And if you have multiple overridden OnGUI methods, they are even more common)

I understand that GC needs to do its job, but correct me if I’m wrong, such huge spikes shouldn’t be caused by an empty overload of OnGUI function.

So my question is: Any way to get around this? Other than using 3rd party GUI system.

You seem to forget one elemental part in the whole thing:

Start, Update, LateUpdate, FixedUpdate, OnGUI etc are not functions. They are SendMessage targets (thats how these functions are called basically by the engine, though a bit more optimized) as such they create an overhead.
In case of OnGUI, this overhead though is quite a bit larger, because OnGUI gets called once per event and potentially allocating the event as the “OnGUI phase” starts.
Also it has to initialize the extra state within the engine (gui happens distinctly after all the regular rendering has passed etc) which has an additional overhead (thats likely the BeginGUI part you see)

General rule is: don’t have ongui, update, lateupdate and fixedupdate in if you don’t use them.
NEVER have them in with an “if( bla ) return” or direct return cause the major overhead has been payed at that point already!

that the whole stuff shows up as spike is likely caused by the fact that it is about the only thing that causes alloc and dealloc so there is no other stuff going on that would make the spikes become just minimals differences, showing them “out of scale” at the moment

2 Likes

I know what you mean dreamora and it’s no because of that. The source of my problems is a much larger scene with almost 2000 draw calls, dozens of scripts and pretty much an entire game. And these spikes still occur and are very noticeable.

They disappear immediately after I disable every last script that overloads OnGUI. (Even if all that is remaining is a single lone script with empty OnGUI overload)

Edit:
And just for comparison here’s that same scene running at nice 120 fps with all OnGUI scripts disabled.

If I add that “empty” script from my first post, I immediately end up with something like the first image from this post, with FPS being around 60 and spikes to 15.

Nobody else has this problem? It definitely isn’t isolated to my PC as my colleagues have the same issue.

I have the same problem.

“General rule is: don’t have ongui, update, lateupdate and fixedupdate in if you don’t use them.
NEVER have them in with an “if( bla ) return” or direct return cause the major overhead has been payed at that point already!”

I assume you mean that this would be bad:

void Update()
{
   if (thing_is_off || some_other_condition)
      return;
   else
   {
     do_something_interesting.....
   }
}

??
If so, how would you go about it?

He probably meant by using enabled = false instead, however that’s not an option when you need e.g. LateUpdate but don’t need Update.

I have the same problem.

Any code examples are welcome! :slight_smile:

I have the same problem, and yes, it’s OnGUI fault too.
I’m implementing what i have done in another way , but from what I can see the solution is to go around the problem, and implement your stuff in another way.
I don’t know if this is a bug or not but, can’t you implement what you have in OnGui somewhere else ?

Well we’re extending some of the community sprite GUI managers to get avoid this problem.

But if we can use those to achieve the same functionality as OnGUI, without spikes, then i don’t see why Unity can’t also. So I like to consider this a bug.

BUMP!

any update on this? I’m having the same problem.

For me though, I get steady framerates, but sometimes seemingly at random this will start happening to me.

I have several scripts with an OnGUI function… in fact, I have a whole list of by default disabled scripts that are enabled and disabled by an Overlay Manager…

I don’t understand… how CAN you avoid using update, lateupdate and so on. Aren’t these the only way you can have any code running?!

1 Like

you can merge related code to be called from a manager. For AI for example thats normal, you don’t want the ai think to tick each frame so you have a manager that knows when to tick what and can also facilitate “team related ai” for example

No; you can use things like coroutines and InvokeRepeating.

function Start () {
    while (true) {
        transform.Translate(Vector3.right * Input.GetAxis("Horizontal") * 10.0 * Time.deltaTime);
        yield;
    }
}

–Eric

Seems pretty horrific.

1 Like

Well, that was essentially just a replacement for Update. Real usage would be something more like, e.g. to put in a delay after firing a shot (from here):

var shotDelay = .5;

function Start () {
    while (true) {
        while (!Input.GetButtonDown("Fire")) yield;
        // Fire bullet here
        yield WaitForSeconds(shotDelay);
    }
}

Update is for stuff that runs every frame, and it turns out you don’t often actually want stuff running every single frame, so I rarely use Update for much, since it’s a lot easier to schedule events with coroutines.

–Eric

Hey guys i know there are some experienced bloggers in this forum talking about this. But when can we wise up that a product like unity offering a GUI which Fxxcksss up the FPS so badly due to garbage collection issues must be seen as very inefficient/bad architecture model under the hood. I shelled out for the pro license and require it for MMO gaming which needs inventory windows, chat windows. Where do i go from here, can someone tell Unity to put a “Please dont purchase if you want to do this in a game” on their buy screen"" frankly i’m frustrated since i will have to start going elsewhere for a work around. GUI is like Err Duhhh if im not going crazy an essential component of any dev environment these days!!! Wake up guys

Well this is a happy collection of programmers. Just wanted to throw my “yep this happens to me too” in with the lot, and its a game ending issue for me. So, I’ve already purchased Above and Beyond’s Sprite Manager 2 and EZ Gui systems, and will send the next week attempting to check and see if that helps any. If anyone has already tried this, please speak up, but if not I’ll report back in a week or so.

I’ve gone down the Flash Unity Integration path with much success. It simply means i can avoid the dreaded OnGUI() which is causing all the pain. In the process i discovered that Flash GUI components are so much easier to work with (e.g. mx.tree component) than building with Unity GUI.

The solution is not for everyone though

  1. Must be using the Unity Web Player and Flash Plugin Player/ or browser javascript in a browser.
  2. You can design your app such that the GUI Interfaces remain outside the unity web player.

If anyone interested i might be able to get some useful links and sample code of this working.
I know there are links around showing this…

Indeed this happens to me as well. Im glad i stumbled on this thread. I just thought it was me and that unity overall was “twitchy” even though i have constant framerates of 300+

OnGUI really seems to be the issue and perhaps coding in a way to even need garbage collection is bad i suppose. Like say, im getting these spikes just from having a custom cursor on the screen.

Interesting.

Victory is mine. Using EZGui seems to avoid the GC spike, and after looking at how EZ Gui does thier implementation, you can do something similar without spending any money. They basically just set up a system to use regular game objects as their GUI widgets, operating everything without a call to OnGUI. So, if you just use game objects for you GUI and lock them to the camera, you could probably do the same thing without too much difficulty.