Search Unity

Garbage for every OnUpdate when using ECS

Discussion in 'Entity Component System' started by BonneCW, Jan 10, 2020.

  1. BonneCW

    BonneCW

    Joined:
    Jan 22, 2017
    Posts:
    123
    Hey there,

    I'm relatively new to ECS and wonder if it's okay that every system I have allocates memory each frame. E.g. a very simple one for energy regeneration:

    Code (CSharp):
    1. using Unity.Entities;
    2. using UnityEngine;
    3.  
    4. public class EnergyRegenerationSystem : ComponentSystem {
    5.  
    6.     protected override void OnUpdate() {
    7.         Entities.ForEach((ref EnergyData data) => {
    8.             if (data.CurrentEnergy >= data.MaxEnergy) return;
    9.  
    10.             data.CurrentEnergy += data.RegenerationRate * Time.deltaTime;
    11.  
    12.             if (data.CurrentEnergy <= data.MaxEnergy) return;
    13.  
    14.             data.CurrentEnergy = data.MaxEnergy;
    15.         });
    16.     }
    17.  
    18. }
    19.  
    It seems when ForEach is executed a new NativeArray and underlying a new List ist created.

    I'm using Unity 2019.2.17f1 on Windows with Entities 0.1.1.

    Is this a bug, intention or am I just doing something wrong?
     
  2. daschatten

    daschatten

    Joined:
    Jul 16, 2015
    Posts:
    208
    Profile this in a build, should be gone there. This is due to safety checks in editor.
     
  3. Lucas-Meijer

    Lucas-Meijer

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    175
    If you use the new Entities.Foreach feature in JobComponentSystem instead of ComponentSystem, you can do this without garbage and with burst.
     
    deus0 and Diukrone like this.
  4. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    Unless I'm mistaken I think it's from the lambda - the old ComponentSystem doesn't do the compile time magic to avoid the GC allocations when using lambdas.
     
  5. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    As a workaround im creating local function and put them in Delegates then pass the Delegates to the Entities.foreach which prevent the creation of GC on every frame. This is working for me.
     
  6. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    Like Lucas said you should really just be using JobComponentSystem now, it lets you do the foreach lambda with no allocations and it will run faster than ComponentSystem even for main thread code. See the dots pong tutorial for an explanation.
     
    Last edited: Jan 12, 2020
  7. BonneCW

    BonneCW

    Joined:
    Jan 22, 2017
    Posts:
    123
    Is it worth it when there aren't many entities for the system?
     
  8. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    Yes. In the latest version of Entities JobComponentSystem will run faster and avoid the allocation problems ComponentSystem has, so there's no reason not to use it instead. I wouldn't be surprised if ComponentSystem ends up being deprecated at some point. Just watch the video I provided in my previous post for a better explanation.
     
    Opeth001 likes this.
  9. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    It’s already. Joachim mentioned that they will remove ComponentSystem and JobComponentSystem will be one full covering solution for main thread and jobified code.
     
    Sarkahn and florianhanke like this.
  10. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    Nice!! i didnt know about it. im going to watch it now :)
    i like this way Unity's is initiating it's Community to ECS!

    there is something im not understanding in this new way of writing Multithreaded Code by using the Entities.ForEach to replace the old way of doing things like 'IJobParallelFor...'.
    in the video he disabled the BurstCompile just because it's using a static not ReadOnly variable inside the job. which is really a bad Approach, because Burst is amazingly optimizing performance even on main Thread.
    in the old way it's as simple as passing a copy of the value as readonly to the Job,but how to do this in the new ECS way of scripting ?
     
  11. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    Basically you assign any outside data to a local variable just before you run the ForEach and then use that local variable in the ForEach as normal. If you need to it to be accessed as read only, you do

    Code (CSharp):
    1. var something = Whatever
    2. inputDeps = Entities.
    3.     WithReadOnly(something).
    4.     Foreach(...
    The manual page for the new ForEach is actually surprisingly thorough and detailed. Highly recommended for learning the new syntax.
     
  12. yossi_horowitz_artie

    yossi_horowitz_artie

    Joined:
    Jan 30, 2019
    Posts:
    87
    I'm finding lots of resources for the new syntax, but where can I find more details about how the compiler avoids creating garbage in this situation?
     
  13. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    982
    Not much for now except for the source code. Just assume that unity replaces this with code generation which generates code that avoids garbage.
     
  14. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    DOTS -> DOTS Compiler -> Open Inspector. Will show you which code will be generated for systems, you can inspect and see how it works.
     
  15. yossi_horowitz_artie

    yossi_horowitz_artie

    Joined:
    Jan 30, 2019
    Posts:
    87
    Does Tiny use the same compiler, or for now, will garbage still be generated in Tiny if you use delegates?