Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-use Entity.Id #81

Merged
merged 3 commits into from
Jun 7, 2015
Merged

Re-use Entity.Id #81

merged 3 commits into from
Jun 7, 2015

Conversation

dogwatch
Copy link
Contributor

No description provided.

@Maximusya
Copy link
Collaborator

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
Copy link

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

@Maximusya
Copy link
Collaborator

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.

  • given just Entities retention with low RemovedEntitiesRetention value - most of those entities would be eventually be GCd, freeing memory; new entities would receive even greater Ids, causing some Bag<IComponent> containers to grow.
  • given just Entities retention with high RemovedEntitiesRetention value - all of those entities would be kept for future reuse; memory occupied by Entity objects would remain occupied, just the memory occupied by IComponent objects would be freed after GC - but I guess the memory occupied by IComponent objects is what makes the most memory footprint.
  • given Entities retention with high RemovedEntitiesRetention value PLUS Ids retention - all of those entities would be kept for future reuse etc - Ids retention would not even come into play;
  • given Entities retention with low RemovedEntitiesRetention value PLUS Ids retention - most of those entities would be eventually be GCd, freeing memory; new entities would receive Ids in range of reused Ids, thus Bag<IComponent> containers will not grow.

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
Copy link

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
Copy link
Contributor Author

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
Copy link
Collaborator

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
Copy link
Contributor Author

@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

tpastor added a commit that referenced this pull request Jun 7, 2015
@tpastor tpastor merged commit 239c39c into thelinuxlich:master Jun 7, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants