Search Unity

Space-Partition Query vs Garbage Collection ?

Discussion in 'Scripting' started by chansey97, Aug 26, 2014.

  1. chansey97

    chansey97

    Joined:
    Sep 21, 2012
    Posts:
    59
    Hello,

    I'm developping a game which using Space-Partition to query units in range.

    My method like following:

    Code (CSharp):
    1. Boolean GetUnitsInRange(out List<UnitID> list, Vector2 minPos, Vector2 maxPos);
    2. {
    3.   list = new List<UnitID>();
    4.   //Omitting some code
    5.   if (Condition)
    6.       list.output.Add();
    7.   //Omitting some code
    8. }
    9.  
    Then My steering-behavior("Separation") algorithms uses GetUnitsInRange:

    Code (CSharp):
    1. void SimulateStep()
    2. {
    3.   //Omitting some code
    4.   var unitIDList = null;
    5.   if(!GetUnitsInRange(unitIDList, rangX, rangY))
    6.   {
    7.       var otherPosList = new List<Vector2>();
    8.       foreach(var unitID in unitIDs)
    9.       {
    10.           var unit = UnitManager.Find(UnitID);
    11.           if(unit!=Self)
    12.               otherPosList = units.Add(unit.position);
    13.   }
    14.  
    15.   var steeringForce = SteeringBehavior.Separation(position, otherPosList)
    16.   ApplySteeringForce(steeringForce); //will uodate unit postion internal
    17.   }
    18.   //System.GC.Collect(); <--- I don't know whether should i call GC???
    19. }
    20.  
    My question is :
    There are 2 times allocation in SimulateStep, and SimulateStep will be call in unity Update.

    So...every unit (which has Separation behavior) will generate garbage in every frame!

    But they are only temp memory in stack logically.....

    I don't know whether should i call GC at the end of SimulateStep?

    After read some paper, manay garbage collector support Young Generation to deal with this problem, but it depends on VM implement.

    Is there some way to contol Young Generation manually or preallocate some memory for this kind of temp memory (assign object new from that small heap memory insteadof system heap. Not object pool) ?

    EDIT:
    System.GC.GetGeneration could get generation in VM.
    and Call System.GC.Collect(0) == call Young Generation manually?

    GC.Collect Method (Int32)
    Forces an immediate garbage collection from generation 0 through a specified generation.

    The most recently created objects are in generation 0 and the oldest objects are in a generation less than or equal to the generation returned by the MaxGeneration property.

    Is there any best practice for this method usage?

    Thanks.
     
    Last edited: Aug 26, 2014
  2. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    It's good practice to never ever call GC.Collect directly. Let the gc figure out when to run. Otherwise you'll shift stuff to a later generation which can cause more problems. Calling GC.collect in update is just insanity. Like no. no. no.

    There are many things you could do to prevent garbage in first place or make this better. GC.Collect is not the answer.
     
  3. Cygon4

    Cygon4

    Joined:
    Sep 17, 2012
    Posts:
    382
    Unity is using Mono 2.6, which does not have a generational garbage collector (SGen was introduced with Mono 3.0).

    I would change your GetUnitsInRange() method. It is allocating a new List<UnitID> each time. If you reuse the same list, you can avoid the garbage:

    Code (CSharp):
    1. void GetUnitsInRange(Vector2 minPos, Vector2 maxPos, IList<UnitID> units);
    2. {
    3.   units.Clear();
    4.   //Omitting some code
    5.   if (Condition)
    6.       units.Add(someunit);
    7.   //Omitting some code
    8. }
    Then just keep reusing the list:

    Code (CSharp):
    1. private IList<UnitID> unitsInRange;
    2.  
    3. void SimulateStep()
    4. {
    5.   if(this.unitsInRange == null) {
    6.     this.unitsInRange = new List<UnitID>();
    7.   }
    8.   GetUnitsInRange(rangX, rangY, this.unitsInRange);
    9.  
    10.   for(int index = 0; index < this.unitsInRange.Count; ++index) {
    11.     // ...
    12.   }
    13. }
    Also try to avoid foreach if you can use for, since foreach calls GetEnumerator(), creating another object that becomes garbage later.

    Never call GC.Collect() on a per-frame basis. You will destroy your frame rate and not gain anything.
     
  4. chansey97

    chansey97

    Joined:
    Sep 21, 2012
    Posts:
    59
    Very thanks, it's useful!