- Home /
Why is GC.Collect() very slow?
Hi There
I am developing for iOS, so I want to have as few spikes as possible...
I see that I am growing my allocated heap at a rate of a few K every few seconds. I cannot at this stage determine why this is. The MAX heap size is tiny also, I have around 500K of headroom before a collect will occur.
Following the advice I had read in the Unity docs on maintaining performance I added a GC.Collect() every 30th frame. However this seems to take a huge amount of time, like 60MS every single time I issue a collect (iPhone 3G S) and there's typically only a few K to actually collect. I was rather expecting more in the region of the 5MS suggested.
I am enabling ENABLE INTERNAL PROFILER to see these numbers.
Is this because we have a big app (maybe 50MB) and so we have a small heap size and a lot of RAM to check over during a collect?
Has anyone else experienced this?
Also, I have assumed that the heap sizes are in bytes, could anyone confirm this?
Thanks
Bovine
From what I read and been told, calling GC.Collect() yourself is a bad idea as it 'breaks' the Garbage Collector's predictions and estimations, which are pretty autonomous. Unless you had GC problem to start with, you should leave it alone. And if you're having problem with GC, you might be attributing too many new objects, perhaps the project could use optimization?
I was reading this area of the docs:
http://unity3d.com/support/documentation/$$anonymous$$anual/iphone-Optimizing-Scripts.html
But I think I misunderstood. Where the heap is small, so 200$$anonymous$$, then it is 'cheap' to call Collect. But my heap is more like 3.5$$anonymous$$B which is not so small and I think hence the 60$$anonymous$$S.
I am going to try the suggestion of forcing a larger heap size as this will allow me to call Collect() between levels/when static screens are displayed and reduce the frequency of collects, but I am $$anonymous$$dful of the fact that it will be all the more painful when it does kick in...
There are now NO new objects allocated in the script code besides return values from Coroutines and I've no idea how expensive these are. (i.e. yield return new WaitForSeconds()). I could consider using a different strategy, a reusable equivalent for WaitForSeconds() that checks whether it needs to be called, but this isn't as cheap as never being called. Still if returning new objects is the cause, then I may try that as it's a direct swap out and means the return value can be re-used and not allocated each time - why isn't there already one that works this way please?
The main culprit was naive string concatenation which was eating around 80$$anonymous$$ per second, but I cannot find anywhere else I am doing any of this. Still it's down to 3$$anonymous$$ per second but with a small heap I'm going to judder every few $$anonymous$$utes. It may be acceptable....
Thanks Bovine
It's worth noting that the practise of calling the garbage collector was one recommended in a Unity doc, possibly the one linked, though that seems to be broken now. $$anonymous$$y understanding is that the garbage collector under Unity (probably just under mono) behaves quite differently and so doing GC when say, showing a meny and pausing the game, is quite safe.
Answer by Bovine · Dec 23, 2011 at 02:19 PM
Okay, so I'll answer my own question here, sorry it's probably obvious but hopefully will help someone else:
See the docs here:
http://unity3d.com/support/documentation/Manual/iphone-Optimizing-Scripts.html
It's slow because as mentioned in this video...
http://unity3d.com/support/resources/unite-presentations/optimizing-for-unity-iphone-1.5.html
...the whole heap has to be considered and as my heap is not 200K but 3.5MB it's like 10 times the cost.
It seems calling Collect() is best done between level loads and obviously it's best to avoid this full stop.
Thanks Bovine
Answer by Ruedii · May 09, 2017 at 06:14 AM
Sorry for the late reply, but the question is still relevant.
Unity3D has been using the same GC technology since it was first created. Since then there have been two generations of GC technology. However, due to licensing issues Unity3D chose not to update this, despite hordes of gamers and developers saying they should.
There are ways to reduce the problem though, see the other reply for your best bet there.
That's the bad news, and is why this has been such a major problem for Unity developers.
Fortunately, though, those licensing issues have finally been resolved and according to the dev blog, Unity is going to be moving to a new GC model in future revisions. There are still some binary backend hooks to work out, and some things related to optimization and profiling, as Unity has become quite dependent on the old GC system.
Without getting into detail, the new GC system will have far shorter world-stops and main-thread stops, and that will reduce problems drastically. However, it is still a very good idea to optimize for GC handling in interactive games.
Your answer
![](https://koobas.hobune.stream/wayback/20220613062331im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
How do I get my game to run faster? 4 Answers
Shader.Parse overhead 0 Answers
Active rigidbodies and number of Contacts 1 Answer
GFX.WaitForPresent takes the most time? 1 Answer
How to get OpenGL frame capture under XCode in Unity4? 0 Answers