The Garbage Collector (GC) is not really an obstacle to implement an Entity-Component-System (ECS) architecture.
All you need is a root object for your ECS. It would hold references to the containers you use for your components (and references to your systems, if that makes sense in your implementation). Those containers will likely hold arrays of components, which is how you have the components contiguous in memory. Which is important for for cache optimization (and yes, that remains important for performance regardless of GC).
As long as you have a reference to the root, the GC will not collect any of it.
In fact, there isn't a lot of manual memory management in ECS. Usually, you will not store your components by de/allocating in the heap (because then you lose control over memory layout), instead you will be storing components as elements of arrays. Then the memory management is about allocating the arrays, for which you would use a an Object Pool pattern.
The obstacles an object oriented language could pose to implement an ECS are others. For instance, if the language does not allow you create custom value types (e.g. C# struct
), it means that your arrays would only hold references to the actual components. And those components would be stored elsewhere. Thus, you lose that cache optimization you want.
I also want to mention that depending on the language, you may need to pay attention on whether or not arrays guarantee that values are contiguous in memory. Some runtimes would offer sparse arrays or other structures by default.
An object oriented approach would suggest that an entity is a container of components. And semantically, that is the case. However, implementing it that way means that components of the same kind are not contiguous in memory. Instead, the entity will be an integer, which you would use to find its components. Unless you can't have chunks of contiguous in memory anyway, then go ahead and implement the ECS on more object oriented grounds.
By the way, if your language is one of those that poses obstacles, chances are it is a dynamic language where you can add components to an object at runtime directly. Which means you don't have to implement that part. Also, you would have a more idiomatic syntax.
Which reminds me, cache optimization is not the only benefit of an ECS. Thus, there is still value in an ECS even if you don't have chunks of continuous memory.
What is the value of an ECS without cache optimization? First, composition. For starters, you can add and remove components at runtime, plus you can iterate over all the entities that have components of a given kind. This allows you to have components work both as state and as messages. And second, going against the object oriented approach, having the systems separate from the entities help in keeping your code easier to manage. Without that, in order to not repeat code, behavior tends to accumulate in a base class for all entities. Base class which has to deal with all cases.
By the way, I don't to suggest that ECS is the only solution, nor that everything should be in an ECS. There is also value in having some aspect of a game exist outside of an ECS. Similarly, remember that making games without an ECS is perfectly possible.
I'll recommend you to watch the video: RustConf 2018 - Closing Keynote - Using Rust For Game Development by Catherine West and the response video Rant: Entity systems and the Rust borrow checker ... or something.. Although, these videos are about Rust, they manage to do a good job of explaining the problems of an orthodox object oriented approaches and the memory management challenges in implementing an ECS. You will hear about the Rust borrow checker… If you are not familiar with Rust, suffice to say, that the borrow checker, is part of the Rust compiler and it is there to make sure that your memory management is correct and safe. Code has ownership of memory when it is responsible for de-allocating, and borrowing means to access some memory without taking ownership. Could the owner de-allocated the memory while borrowed? The borrow checker, well, checks that.