thelinuxlich / artemis_CSharp

Artemis Entity System Framework ported to C#
Other
341 stars 78 forks source link

Re-use Entity.Id #81

Closed dogwatch closed 9 years ago

Maximusya commented 9 years ago

What is the point of reusing Id in addition to reusing "Entity object + it's Id"? There is already reuse of "Entity object + it's Id" you know it, right? Можно по-русски

KellanHiggins commented 9 years ago

Not exactly sure what the point of this is. Can you explain the reasoning behind it?

Maximusya commented 9 years ago

As @dogwatch said

Пока количество удаляемых Entity меньше RemovedEntitiesRetention, они попадают в removedAndAvailable для повторного использования, а если удаляемых больше, мы теряем их entity.Id для использования в ActiveEntities.

While the number of Entities removed is less than RemovedEntitiesRetention, they end up in removedAndAvailable for future use, but if the number is greater, we lose their entity.Id for its use in ActiveEntities.

I guess the reasoning behind desire to reuse just entity.Id is to neutralize (to some extent) constant growth in size of Bag<IComponent> containers (accompanied by internal new T[newCapacity] and Array.Copy). RemovedEntitiesRetention serves same purpose - in addition lowering GC pressure. But Entities retention has greater memory footprint than Ids retention.

I can only imagine a narrow case when additional Ids retention (doubtfully?) comes in handy: at some moment there is a burst in shortlived entities creation.

Only the last case is affected by Ids retention. But the size of those int[] arrays is doubtly the case of optimization.

Or do I miss some ordinary case? And having unbound Ids retention is a cheap built-in stuff that sometimes may come in handy?

KellanHiggins commented 9 years ago

Thanks for the explanation and translation, but I think this is above my head with regards to memory management within C#.

How is Bag<IComponent> going to grow? I guess I am not too clear how C# keeps track of components and entities in EntityWorld.

dogwatch commented 9 years ago

Example. Each call Heartbeat() results in the loss of a one entity.Id.

    class Program
    {
        static EntityWorld world = new EntityWorld();
        static int poolSize = world.EntityManager.RemovedEntitiesRetention;

        static void Heartbeat()
        {
            // Create RemovedEntitiesRetention + 1 entities.
            for ( int i = 0; i < poolSize + 1; ++i )
                var entity = world.CreateEntity();

            Console.WriteLine("ActiveEntities: " + world.EntityManager.ActiveEntities.Count);
            Console.WriteLine();

            for ( int i = 0; i < world.EntityManager.ActiveEntities.Count; ++i ) {
                var entity = world.GetEntity(i);
                if ( entity != null )
                    world.DeleteEntity(entity);
            }

            world.Update();
        }

        static void Main(string[] args)
        {
            Heartbeat();
            Heartbeat();
            Heartbeat();
            Heartbeat();
            Heartbeat();

            Console.ReadKey();
        }
    }

Output:

ActiveEntities: 101

ActiveEntities: 102

ActiveEntities: 103

ActiveEntities: 104

ActiveEntities: 105

@KellanHiggins

How is Bag<IComponent> going to grow?

To accommodate new entity.Id

Maximusya commented 9 years ago

OK, you suggested another case: long running process. Without full Ids retention it will crash eventually with OOM.

Entities retention can be turned off by setting EntityManager.RemovedEntitiesRetention to 0. Do you think there should be means to do the same with Ids retention? EntityManager.RemovedEntitiesIdsRetention?

I remember the cases when we turned Entities Retention off to get rid of Ids reuse: we had a bug(?) in Systems architecture when sometimes code kept a "reference" to deleted entity's Id and then later tried to get an entity by Id - but got a fresh born one. It was a "quick fix" back then to just turn retention off.

dogwatch commented 9 years ago

@Maximusya

Entities retention can be turned off by setting EntityManager.RemovedEntitiesRetention to 0. Do you think there should be means to do the same with Ids retention?

No. You can not lose indexes. And why if identifierPool.Capacity will always be less ActiveEntities.Capacity?

I remember the cases when we turned Entities Retention off to get rid of Ids reuse: we had a bug(?) in Systems architecture when sometimes code kept a "reference" to deleted entity's Id and then later tried to get an entity by Id - but got a fresh born one. It was a "quick fix" back then to just turn retention off.

Maybe, maybe... Look:

        static void Main(string[] args)
        {
            var world = new EntityWorld();

            world.EntityManager.RemovedEntityEvent += (Entity oldEntity) => {
                var newEntity = world.CreateEntity();

                Console.WriteLine(oldEntity == newEntity);
                Console.ReadKey();
            };

            var entity = world.CreateEntity();
            world.DeleteEntity(entity);
            world.Update();
        }

Output: True

;D