Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Mono garbage collection, can I get a summary?

Discussion in 'General Discussion' started by jackmott, Feb 13, 2014.

Thread Status:
Not open for further replies.
  1. jackmott

    jackmott

    Joined:
    Jan 5, 2014
    Posts:
    167
    I've seen lots of comments referring to terrible garbage collection performance. Does anyone have a technical summary of how/why it is bad? Or perhaps a link to technical performance comparisons discussion about it?
     
    jpthek9 likes this.
  2. Ostwind

    Ostwind

    Joined:
    Mar 22, 2011
    Posts:
    2,804
    There are posts/blogs etc about it all around net but in short the more garbage you produce in your game the more often the collector kicks in causing framerate drops or freezes. On mobile games its horrible thing as it can be seen more clearly and with less garbage than on desktop game.
     
  3. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    1. the more garbage you create, the more often the game pauses *everything* for n millisecs to collect it.
    2. n millisecs - n will increase depending on how many objects you have in memory that potentially can be collected.

    So it's not only how often it will run, but how severely it will run. Pretty much a disaster that requires careful coding to get around at the moment. It requires so much careful coding that it is pointless using garbage collection in my view. But that's what c# uses so...
     
  4. jackmott

    jackmott

    Joined:
    Jan 5, 2014
    Posts:
    167
    I was just curious if a better garbage collection would make any substantive difference. Like if you get a frame rate hiccup of a half second instead of 1 second, well that doesn't really matter. I haven't run into it being an issue with my game, but my game isn't very demanding and I am not on mobile! I am familiar with how quickly you run into memory limitations on mobile though.

    Certainly it is amusing that now for certain applications you have to put as much effort into object pooling as you used to put into not leaking memory!
     
  5. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Complexity plays a role as well. You may have 20,000 objects or 100,000 objects and that isn't going to make a huge difference in garbage collection time. However, if you have 20,000 objects that all cross reference eachother... that will take more time for collection than 100,000 objects that don't reference anything else. This is because the garbage collector must follow those reference paths to make sure all objects referenced by the primary object are out of scope before it can consider the primary object out of scope.
     
  6. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,437
    I admit, I havn't taken much time to read a whole lot about the garbage collection in Unity, however I know for a fact my code is probably not optimized perfectly with garbabge collection in mind.

    For instance, I heard arrays generate garbage fairly easily. If that's true, I don't know how to avoid generating garbage, if it means I can't use arrays -- because arrays are almost a necessary tool I need for my current game. The other thing is, I don't have Unity pro, and so I don't have access to a good profiler that could probably tell me where the garbage is and what's generating it the most lol.

    So, I guess that's why game developers like to code in C++ is because they can control their own memory management (from what I hear). I would like to learn a lot more about how to code in order to keep garbage collection to a minimum. Yeah, I'm sure there's a few articles online, but probably nothing in-depth about Unity, garbage collection, and workarounds specifically or practically.
     
  7. MarkrosoftGames

    MarkrosoftGames

    Joined:
    Jan 5, 2012
    Posts:
    442
    garbage in = garbage out
     
  8. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Technical Summary: It sucks.
     
  9. Smooth-P

    Smooth-P

    Joined:
    Sep 15, 2012
    Posts:
    214
    Yes, it would make a HUGE, HUGE, HUGE, HUGE, HUGE difference. Unity is using what could be considered a "proof-of-concept" garbage collection algorithm that might be used in a project for an upper level CS course as it's very simple to integrate. Even the Mono docs from the time it was released stated that it was horrible and shouldn't be used in production systems. The current versions of Mono, Java, .Net, etc, etc use what are called generational algorithms which can collect short-term garbage much more quickly and with less of a pause. And truly good GCs that are designed for low-latency applications have an extremely short "stop-the-world" phase and then use threading and locks while the hard work is done so user threads don't pause for the whole the GC cycle, but only wait for locks where needed.

    Imagine if every time you took out the trash in your house you had to check if EVERY SINGLE ITEM in your house was trash. So the fridge, the stove, the TV, all the knick-knacks, every fork, spoon, and knife, your toothbrush, every single item in your house had to be checked. That's what Unity does.

    A generational GC understands that newer things are more likely to be trash than older things, so it will quickly and frequently check if the McDonald's bag you brought in last night is trash to keep things tidy, but very rarely take the time to check if the TV or fridge are garbage.

    And GCed languages are sometimes used in high-volume trading, where less than a ms could mean the difference in making or losing millions of dollars. Anyone saying GCs aren't good enough for games doesn't understand how fast and non-blocking a good GC can be.
     
    Last edited: Feb 14, 2014
    ilmario, GlitchedPolygons and Arkade like this.
  10. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,614
    Arrays are just a data structure. It's allocation that causes garbage collection. How you store references to allocated objects really doesn't make a difference (except for where you're using some fancy data structure that does its own allocation).
     
  11. lmbarns

    lmbarns

    Joined:
    Jul 14, 2011
    Posts:
    1,628
    Interesting article on gamasutra linked in the c++ thread about optimizing a game made with unity: http://www.gamasutra.com/blogs/Amir...trying_to_optimize_our_game_using_Unity3D.php

    Which surprised me, I thought foreach was better than for, but they claim the opposite and measured it all with the profiler.
     
  12. Mr.T

    Mr.T

    Joined:
    Jan 1, 2011
    Posts:
    546
  13. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    foreach allocates garbage. It's never been better under any circumstances, as it's a convenience and you'd need to override the enumerator to get it to not spew garbage. A lot of .net/mono stuff is like that. Avoiding allocations is a black art.

    Unityengine itself spawns loads of garbage, take if (gameObject.name == "foo") << this will return a new string to compare (wtf?) instead of just doing a string compare.

    It doesn't seem like Unity will be upgrading to new mono/new GC though otherwise they'd have already done it since it's a subject that's been complained about for years.

    Ideal case scenario:

    - upgrade to new GC
    - also cap how many ms the GC runs for per frame, ie 1ms over several frames.
    - If full, then stall and run as worst case scenario.
     
    Last edited: Feb 13, 2014
    Rosehardt likes this.
  14. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,050
    If you look around you'll find some blogs and threads here that explain the problem. Its some sort of bug with GetEnumerator generating allocations (boxing) in the version of mono we have. It shouldn't do it, but it does.

    C_Memory_Management_for_Unity_Developers_part_1_of_3
     
  15. Smooth-P

    Smooth-P

    Joined:
    Sep 15, 2012
    Posts:
    214
    Yup, the Unity API itself is quite terrible in many cases, creating garbage in places you wouldn't expect and where garbage is completely unnecessary. Like the tag stuff, which I was also doing and never would have discovered on my own. And why they're so sloppy with garbage is mindboggling given they should know how bad the GC is.

    It is quite feasible to get to zero-allocations* in a normal frame where you don't need to build any strings, but you really gotta profile. Of course, you'll spend a lot of time and on-going effort to achieve this and will have tons of productivity reducing boilerplate code, pools for every transient reference type, push tons of stuff around on the stack, etc.

    *This doesn't include the allocations from Unity or any 3rd party code. In my game the only per frame allocations come from ControllerColliderHit, which for some reason isn't a value type, OverlapSphere, which allocates an array, a small number of allocations from nGUI that I couldn't get rid of without a major time investment, and from uLink, who much like UT, have blackbox code, don't seem to understand how to use generics, and are extremely sloppy with allocations. I may eventually write my own simple but efficient networking layer to avoid being reliant on the competence and API design of others for something so fundamental, important, and memory intensive.
     
    Last edited: Feb 13, 2014
  16. Woodlauncher

    Woodlauncher

    Joined:
    Nov 23, 2012
    Posts:
    173
    This was posted in the 'New Mono Version with 4.3' thread, no one commented on it:
    It seems he misinterpreted the commit, they actually removed the licensing text specific to the GC, so it's probably under the runtime license now. Otherwise Unity might have upgraded the GC. Anyone know why they stopped using the MIT license?
     
  17. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Well GC is still a headache for us. Want it to be fixed.
     
  18. Smooth-P

    Smooth-P

    Joined:
    Sep 15, 2012
    Posts:
    214
    Because Unity is making tons of money off of an old version of their code, while Unity's customers are bearing the cost of the bad GC either through programmer time / loss of productivity or reduced performance.

    Why *would* they just gift Unity a good GC that they spent time and money on (for GC / compiler experts with very specific, high level, technical skills and knowledge, not just swill code by the average joe) and has a monetary value tied to the ludicrous size of the gaming / apps industry?
     
    Last edited: Feb 14, 2014
  19. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Because, information wants to be free, man, and open source developers care about the little guy, they're not crooks like those suits at M$ who are just in it for the money. </sarcasm>
     
  20. jackmott

    jackmott

    Joined:
    Jan 5, 2014
    Posts:
    167
    Interesting, so the newer Mono has vastly improved GC, but Unity would have to pay for the rights to update Unity with it?

    Could we all chip in say... $75 a month? ha!
     
  21. Smooth-P

    Smooth-P

    Joined:
    Sep 15, 2012
    Posts:
    214
    Well, from Xamarin's point of view, they probably ARE the little guy. I'd guess Unity has made a lot more money off of their code than they have.
     
  22. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Xamarin's a multi-million dollar corporation these days. I don't think they count as a "little guy" anymore.
     
  23. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    Has GC been improved? I still see huge problems with GC when clearing arrays and lists. For example, in a voxel game I'm clearing array's of 4k items to recycle that chunk but I can see bumps in GC and it is causing some hiccups.
     
  24. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,943
    Smarter coding decisions are far more effective than a better GC. Rather than marking those arrays for deletion by the GC you should be setting them aside and reusing them when you need to store the same data again. Only mark things as unneeded when you won't need them again or may need the memory available in the future.

    By the way this concept is called object pooling.
     
    Last edited: Oct 3, 2015
  25. Stone-Legion

    Stone-Legion

    Joined:
    Aug 16, 2013
    Posts:
    112
    Thanks for that, yes I am using object pooling and I know all about it :) Nonetheless Unity by far has the worst GC algorithms which require extraordinary jumping of hoola hoops when dealing with larger quantities of data.

    This article is proof enough at how bad unity does GC: http://www.somasim.com/blog/2015/04/csharp-memory-and-performance-tips-for-unity/

    I am reusing arrays where possible but the amount of coding hoops you have to overcome just because unity has poor implementation of outdated and faulty GC is ridiculous given we are at Unity 5 now and these problems still aren't fixed.
     
    Ryiah likes this.
  26. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    it's not unity's gc, it's monos. The mono version will be upgraded soon. ot would also help for you to understand why you're generating garbage. You're essentially resizing arrays and dumping references to classes.
     
  27. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Essentially nothing has changed in terms of GC from the date of the OP. Everything in this thread is still relevant.
     
  28. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Mono's GC isn't the best, but most likely you wouldn't notice the improvement you might think if it was better. If large data is a problem it's not so much the GC as what you are doing. No GC will smooth out large allocations/deallocations unless you give it a ton of memory.

    The problem with mono is that it spikes even when object creation is smooth over time.

    A GC can only do so much. Remember allocation is part of the equation also, and a GC can't defer that part really. And a GC can't predict the future. If you have large bursts of deallocation it doesn't know what might come next, so you are forcing it to spike. The GC can either collect it all soon, or wait and hope it doesn't run out of memory. Most GC tuning is usually done by changing the size of internal memory pools used for allocation and then tuning it to say how much time it has to collect objects no longer in use. The larger the internal pool, the more it can spread out spikes.
     
    Ryiah likes this.
  29. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    You can fix some problems with allocation by using a different compiler; for example Alexzzzz's wrapper for the Microsoft Roslyn compiler: https://bitbucket.org/alexzzzz/unity-c-5.0-and-6.0-integration/src

    This will fix the buggy "foreach" from allocating garbage, for example. The newer compilers are better at generating IL that does not perform unnecessary memory thrashing. But the main problem is still the terrible garbage collector, which can not be fixed until Unity upgrades Mono. And though Dustin says they will update Mono "soon", what they've actually said is they will update it only after they finish IL2CPP and have it fully working on iPhone and Android and they have almost full parity with actual .NET runtimes, so I wouldn't expect it for at least another two years.
     
    Ryiah likes this.
  30. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    I want to add a new one I just found, that was driving me crazy. I haven't seen it mentioned around.
    Action and Delegates. When you have a method that accept delegates, it's easy to pass a function instead and c# won't complain.
    Since I'm used to function pointers from c, I thought it was just passed by value, instead it's an object that is allocated every time you pass the function.

    So create an Action in advance and never pass a method instead.
     
  31. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    GC is not really a issue because we are using managed code, there is nothing that can be fixed.
    But you can follow this simple rules to total avoid it.

    1. Allocate only ones.
    2. Cache instance of other classes, and GetComponent
    3. Dont use public properties or fields if you don't have to.
    5. Avoid using ToString in frame related methods
    6. Use object pooling.
    7. Don't use more than 1-3 canvas.

    But what i would like to see is petter performance of the new GUI. (CanvasRenderSynctrans.. = wth did they do)
     
    Last edited: Oct 8, 2015
  32. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    Please don't tell me that Canvas allocate memory.
     
  33. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Yes and no. When the .NET Profile upgrade happens sometime in the future there will be improvements. Newer iterations of the GC are more efficient and better tuned. We may even get some options to tune the GC a bit ourselves to change the frequency at which GC happens. And newer versions of the compiler actually do a little better job of inlining code and generating more efficient IL. So there should be performance improvements across the board eventually.
     
  34. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    Not directly it generates allot of calls (more than other things in your project), but i seen strange GC happen in relation
    to canvas without any good answer to what is going on. Removing the canvas seems to confirm this.
     
  35. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    You may be right on this, but i can tell you i have almost zero GC allocation in my projects with just the standard compiler.
    If you have allot of GC clean-ups happing, i think you can manage when you want this to happen.
    GC.Collect(); ( i could be wrong with this on Unity 5+)
     
  36. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    You're correct. GC.Collect is actually not a bad method to use between scenes if you have to do some heavy allocation to setup your scene, such as populating an object pool.
     
    Ironmax likes this.
  37. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Sort of. GC.Collect can make a collection cycle run early. That's useful to clean up at the end of a scene or when the game is paused or as part of a loading sequence.

    But you currently have no control over forcing the GC to run later. If the system wants to GC, it will GC.
     
    Dustin-Horne likes this.
  38. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    yeah the system will collect when it wants to collect, because is cleaning up blocks in the memory that are no longer in use,
    If you follow the steps i wrote you wont have issue with GC, it will happen, but not impact your game in any way, example 64kb allocation wont cause any performance issue. I am sure there are room for improvements but you can avoid it just fine.
     
    Last edited: Oct 8, 2015
  39. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Yeah I'm looking forward to the day when I have a choice in allocations in a big 3D game :) a lot of the Unity api generates garbage. I'm pretty familiar with it having released several mobile titles without garbage allocations. The problem is for some things, you can't avoid it without a Unity source license.

    In other situations you *don't want to avoid it* because pooling that far and preallocating that far, puts you out of ram on mobile. Or takes too much performance on open world titles. There's limits you haven't begun to consider.

    In C++ we manage ram ourselves so there's no problem. In Unity you can't do that, but the requirement of allocating and deallocating does not change, there are often times where this is the best of the worst solutions, so therefore improvements are needed. Unity thankfully knows this too and are working on it.

    My comment was in 2014, and finally changes are trickling through.
     
  40. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    GC has become better with Unity in the last version no doubt about it, but if your foundation is based on correct allocation and pool management it doesn't really matter how large your project scales, you should be able to get t zero GC issue, 3D object it self cause no allocation in Unity its just visual "big", in maths its just vector numbers, that is handled by Unitys own c++ API

    I don't believe that Unity can turn a memory managed system with GC to turn in to a memory unmanaged system, rock will still be a rock, but you can change how the rock fall and move. I think its better that Unity focus on reduction calls and how canvas UI renders works now.
     
    Last edited: Oct 8, 2015
  41. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    It's not "correct" to implement your own object pooling system and manually handle allocations in a garbage collected language, it's just something you have to do when the garbage collector sucks as hard as Unity's garbage collector sucks. The whole point of a garbage collected language is that you are not supposed to have to worry about manually allocating and freeing memory in code. At worst, you're supposed to only have to worry about it in critical paths and loops in a small section of your code. People writing their own object pooling systems and writing endless lines of extra code to try to cache every little thing to avoid allocations are not using C# the way it was intended. It's something we have to do only because Unity has a broken garbage collector. It shouldn't really be praised as "correct" coding or thought of as good. Anyone using a .NET runtime from the last decade, like, pretty much every single .NET developer in the entire world except for Unity developers, would look at the ridiculous hoops people jump through to suppress garbage collection and correctly conclude that it was a pointless waste of developer time. Unity anti-garbage-collecting code is a band-aid for a problem that we really shouldn't even need to deal with. I'd bet that if Unity had known thirteen years ago that they were never going to be able to update their Mono runtime and were going to be stuck with the broken garbage collector, they never would have used .NET at all.
     
    jpthek9 and Kiwasi like this.
  42. Whippets

    Whippets

    Joined:
    Feb 28, 2013
    Posts:
    1,775
    @hippocoder said "GC for 1ms across many frames"

    This.
     
    jpthek9 and hippocoder like this.
  43. darkhog

    darkhog

    Joined:
    Dec 4, 2012
    Posts:
    2,218
    Why I get the feeling that Mono's GC (and Java's) would be much less terrible, if we could stop automatic GC with some call and execute GC manually, when our apps are least busy with other things (such as after detecting afk situation or on pause screen/in a menu)?
     
    Ryiah likes this.
  44. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    hehe my friend, I been working with managed systems way before Unity. Dealing with GC is something you learn to live side by side with. There is nothing bad with the current GC system with Unity, I tell you none of my Unity projects, or any other .net framework projects have GC issue, Unity is fine when it comes to this. You must take responsibility for your own code architecture, if you unsure how to do it, ask others, or me ,or download some others ppl work, and go from there.

    Doing allocation in a for loop in Update method ? Yeah sure lets blame the engine

    GC is not your main concern with performance in Unity, how is your call count? Render performance etc. You cant just blame Unity, they are doing a great job with Unity Engine to be honest.

    If you want to make a game in c++ to avoid gc, sure it will steal all your time, and the chances that your game will crash is huge, there is nothing in c++ that will help you or any one you can blame.
     
    Last edited: Oct 9, 2015
  45. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    While that may be true, this thread was specifically about GC. Also keep in mind that it's not always possible to not allocate. This can actually sometimes be compounded when you using a pooling system, though generational GC does help with the issue. The problem isn't necessarily the number of objects you have on the heap, but rather the heap complexity itself. So, let's say you have a large object graph with objects that link to each other and all over the place through references. You may be doing very little other allocation, but when the GC does have to run, the complexity of the heap can make it run slower because it has to follow all of those references every time it runs to see which objects are eligible for collection. So, even if you've pooled, those objects will still be examined every GC cycle.
     
    midworld and Kiwasi like this.
  46. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    I know what your saying and agree, but still its no excuse to not code your project properly, to make sure GC doesn't happen to impact performance (hence my point about calls and other things). Sure we can talk about GC without performance but then it doesn't really matter, and we cant talk about performance without including other related elements. I think we all agree that there can be done things to minimize it, but lets face it, its never going to be any magic where you can do what ever you want in your code.

    With great power comes great responsibility, that is how it suppose to be. You don't want nurfed abilities like Raycast
    just so it supports developers who have zero coding discipline.. You get where i am going with this?
     
    superpig likes this.
  47. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Yes, yes, so have I, and I'm also the king of France.

    Luckily, almost every Unity developer in existence disagrees with you, so Unity will eventually be fixing it.
     
    LazloBonin and Kiwasi like this.
  48. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    With the adoption of IL2CPP, I was hoping that Unity would have been able to improve the GC or even replace it with a more game friendly system.

    e.g. Apple dropped their GC and moved to an ARC automatic reference counting system, no performance overhead as it's done at compile time.
     
    jpthek9 likes this.
  49. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I wonder if ARC would work on a platform that allows code generation at runtime.

    Glancing at it briefly it looks like it still has a bunch of potential traps if you misuse it. The traps are different from a GC. But they are still there.
     
  50. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Nope, it wouldn't support anything generated using Reflection.
     
Thread Status:
Not open for further replies.