Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

GC.Collect lag spikes

Discussion in 'Scripting' started by serbusfish, Sep 13, 2018.

  1. serbusfish

    serbusfish

    Joined:
    Dec 27, 2016
    Posts:
    247
    When testing out one of my scenes every now and again I experience numerous large but brief fps drops, and when I check in the profiler what causes the spike it says 'GC.Collect'. I have no idea what this is, I have never used this in my code and this is the first time I have come across the term. The only thing I can say is that I destroy a large collection of game objects when the first lag spike hits so I suppose this is somehow connected to GC.Collect? If so can someone explain what is happening and how I can get around this problem?
     
  2. GeorgeCH

    GeorgeCH

    Joined:
    Oct 5, 2016
    Posts:
    222
    Unity uses Garbage Collection (GC) to periodically clear out, well, garbage generated by your code at runtime. The faster the garbage accumulates, the more frequency the garbage collector will run, and the more work it will have to do.

    You usually cannot eliminate it, but you can reduce it. Read this for more information. Generally speaking, use the Deep Profiler to figure out where garbage is coming from and work to reduce it. Additionally, you can call GC.Collect() yourself at appropriate moments - for example, when the user is in a menu, they probably wouldn't care about an FPS drop.
     
    ihgyug and Joe-Censored like this.
  3. ToshoDaimos

    ToshoDaimos

    Joined:
    Jan 30, 2013
    Posts:
    679
    Learn about memory management in Unity/Mono. It's a delicate thing, requiring skilful handling.
     
  4. serbusfish

    serbusfish

    Joined:
    Dec 27, 2016
    Posts:
    247
    Thanks this is very helpful, I have a lot of functions in update that aren't cached so it's possible this is the cause of my problems, I will read up on this more and try to cache my functions.
     
  5. GeorgeCH

    GeorgeCH

    Joined:
    Oct 5, 2016
    Posts:
    222
    Generally speaking, you should never, ever make GetComponent calls every frame.
     
    ihgyug likes this.
  6. serbusfish

    serbusfish

    Joined:
    Dec 27, 2016
    Posts:
    247
    I dont understand what my scripts could be generating that would be considered garbage. My game is a fairly simple side scrolling shooter, there isn't that much going on that could be considered advanced or overally complex.

    I tested out using the profiler with a development build and I was getting constant spikes related to 'behaviour update', but none of the scripts within show huge performance usage:

     
  7. GeorgeCH

    GeorgeCH

    Joined:
    Oct 5, 2016
    Posts:
    222
    Break it down using Deep Profiling and you'll find out.
     
  8. WhendricSo

    WhendricSo

    Joined:
    Jan 1, 2011
    Posts:
    171
    Make sure to cache instances in your classes, don't destroy (or create!) things unless absolutely necessary. Especially object references! If you're developing for mobile, it's best to implement object pooling so that you can spawn & destroy stuff without invoking the garbage collector.
     
  9. ruudvangaal

    ruudvangaal

    Joined:
    May 15, 2017
    Posts:
    27
    So how about a simple 'string s=string.Format(...)'. Does that generate garbage as well? It's not easy to get around garbage if you use strings. Hm.
     
  10. WhendricSo

    WhendricSo

    Joined:
    Jan 1, 2011
    Posts:
    171
    Yes, since you're calling
    string s=
    then you're calling it's constructor. If you do that inline inside a member declaration, then you're creating a temporary member that must be garbage collected afterwards.

    If, however, you declare
    string s;
    at the top of the file as a class member, it will only need to be garbage-collected when the class itself is destroyed, usually this happens when the game object that the script is attached to is destroyed, to free up memory for new objects.
     
  11. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,504
    No, that's wrong and misleading.
    string s=
    does not call a constructor or allocate memory on the heap. It declares a variable. If that variable is declared inside a method it will live on the stack and will be cleaned up when the methods end without any issues. However strings are reference types. So the variable only holds a reference to a string instance. This string instance will live on the heap and needs to be collected once nobody is holding a reference to it anymore.

    Furthermore strings are immutable. That means once the string instance is created, it can not be changed or modified, only replaced by a new instance. That means the old one (once all references to it are gone) is up for garbage collection, regardless of where those references were stored.

    As it was mentioned by others, there isn't much you can do against garbage generated from string allocations besides reducing the number of times you create new strings. For example when you show your current score in an UI Text, only update the text when the score has actually changed and not simply every frame.

    There have been approaches to reduce / remove string allocations like the gstring library. Though it can not be used in all cases and you have to be careful how to use it as it uses unsafe code to actually mutate / modify an existing string. Strings can not change their size, so the internal caching is limited. Also using that library will of course require more memory as it keeps several string instances cached internally. Though the point is to reduce the steady allocations and garbage on a frame to frame basis.
     
  12. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    760
    In morden C# you can use Span<char>/ReadOnlySpan<char> for string operation (Since Unity 2021.2). Strings have the AsSpan() method. That can help reduce GC allocation.
     
    egonzaga likes this.
  13. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,900
  14. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    760
    ilmario and Nanomid like this.