I am building a project with Zay-ES and I have about 150 entities that interact with each other, adding and removing some components here and there, like 0-3 components per entity per frame. Nothing really big. Also, some entities (projectiles in-game) get created and destroyed often. Each bears something like 7 or so components.
What I find very soon into the game is this:
Zay-ES internal machinery makes the GC run so often that the game starts to freese every 5 seconds or so.
This is strange to me. I did not think that such a basic operation as creating/removing components should take that much. And I am sure that for an ECS that is a crucial point, since the concept itself somewhat relies on quickly managing the components.
So the question is: by creating and removing entities and adding/removing components from then in the amount of 150 entities, say 7 components per each, and about 25 systems in my ECS currently, I am causing this. Is this normal? Is this a performance bug? Am I missing something?
This is not normal.
Most of the components will be in the young generation and incrementally GC’ed without issue. I’ve run Zay-ES based games for long periods of time without any problems like this.
Most likely cause, (especially if the GC eventually just gives up) is that you’ve grabbed an EntitySet and never called applyChanges()… or you create lots of EntitySets and never release them. (Same applies for WatchedEntities). EntitySets are meant to be held onto for a long time and released when done… and it’s important to memory health to call applyChanges() often (like per frame).
Your screen shot indicates this as the internal concurrent linked queue has grabbed 344 meg and has not released it. I suspect your program will run out of memory eventually. (At least from the partial screen shot we can see.)
Otherwise, the only other thing I can think of is odd GC settings.
An ECS will churn through a lot of RAM but it should be constantly GC’ed incrementally and never build very large. It should never cause a full GC, really.
Oh good to know that, it seems that I did it intuitively correct as I also never had an issue with even much more entities and more component changes per frame.
Indeed, it was that I did not call the
applyChanges() on entity sets for some systems. Did not think that it was crucial for them. Turned out to be deadly! Well, okay, now I apply the changes on an every entity set and things go very smooth!
Thank you very much!
Curious… why would you get an keep a static view of an entity set? Without calling applyChanges(), the entities in the set never change and the set never updates.
Anyway, for EntitySet to work properly, in the background it is accumulating changes. Calling applyChanges() flushes those… else they eventually consume all RAM.
I think that I’ve just missed something. Initially the situation was that some systems were to acquire an entity set on start, and later this set was not meant to add or change the entities, so there was no reason for applying the changes (in my mind). However, the set was meant to reduce because the entities were eventually being destroyed. After I have added the
applyChanges() call, as you have suggested, in every system’s update method, nothing changed in the behavior of the application and the world within it, except that the memory lags have gone.
I am not sure how exactly those changes were accumulating on the entity sets since I was not consciously making them. And the absolute equivalence of the game world behavior before and after adding the
applyChanges() call is a proof that I did not make a logical mistake.
My hypothesis is that when I was destroying the entities, the system created the change sets for the entity sets that were needed to be applied. Since the entities were gone, there was no visual clue as to why that would need to happen and I have missed that point.