docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Optimize structural changes

    Structural changes cause sync points that affect performance. There are also other CPU tasks that Unity must perform during structural changes, which can also impact performance.

    Structural change process

    For example, if you have an entity with two components called A and B, and you want to add a third component called C, you might write the following code:

    // create archetype and entity in a Burst-friendly way
    var abComponents =  new FixedList128Bytes<ComponentType>
    {
       ComponentType.ReadWrite<A>(),
       ComponentType.ReadWrite<B>(),
    }.ToNativeArray(state.WorldUpdateAllocator);
    
    var abArchetype = state.EntityManager.CreateArchetype(abComponents);
    var entity = state.EntityManager.CreateEntity(abArchetype);
    
    // ... Some time later... 
    state.EntityManager.AddComponent<C>(entity);
    

    Adding component C to an entity which has an archetype of AB causes Unity to perform the following process:

    1. Check if an EntityArchetype for ABC already exists, and create one if it doesn't.
    2. Check if the ABC archetype has a chunk free for a new entity. If there's insufficient chunk space, allocate a new chunk.
    3. Use Memcpy() to copy components A and B into the new chunk.
    4. Create or copy the component C into the new chunk.
    5. Update the EntityManager so that the entity which previously pointed to an index in an AB chunk now points to the new index in the ABC chunk.
    6. Use swap_back() to remove the original entity from the AB chunk.
      • Free the chunk memory if the original entity was the only entity in the chunk.
      • Otherwise, update EntityManager with the new index of the chunk.
    7. Clear the cached list of chunks for every EntityQuery that involves that chunk's archetype. The EntityQuery recalculates the list of chunks it refers to the next time it executes.

    The individual steps to perform structural changes aren't slow, but when thousands of entities change archetypes in a single frame, this can significantly impact performance. The processing overhead scales with the number of EntityArchetypes and EntityQueries that have been declared at runtime.

    Structural changes approach comparision

    The following table compares different approaches to structural changes, and the time in milliseconds that it takes to add one component to one million entities with each approach:

    Method Description Time in ms
    EntityManager and query with enableable components Don't add any components, and enable a component that implements IEnableable, which was previously disabled. For more information, refer to Enableable components 0.03
    EntityManager and query Pass an EntityQuery to the EntityManager with AddComponent to immediately add components in bulk on the main thread. 3.5
    EntityManager and NativeArray Pass a NativeArray<Entity> to the EntityManager to immediately add components on the main thread 35
    Entity command buffer and playback query Pass an EntityQuery to an EntityCommandBuffer on the main thread to queue components to add using the EntityQueryCaptureMode.AtPlayback flag. Then execute that entity command buffer (time includes the entity command buffer execution time). For more information, refer to Entity command buffers. 3.5
    Entity command buffer and NativeArray Pass a NativeArray<Entity> to an EntityCommandBuffer on the main thread to queue components to add, then execute that entity command buffer (time includes the entity command buffer execution time). 35
    Entity command buffer and job system with IJobChunk Use an IJobChunk across multiple worker threads to pass a NativeArray<Entity> per chunk to an EntityCommandBuffer, then execute that entity command buffer (time includes the entity command buffer execution time). 17
    Entity command buffer and job system with IJobEntity Use an IJobEntity across multiple worker threads to pass instructions to add components to entities one at a time to an EntityCommandBuffer, then execute that entity command buffer (time includes the entity command buffer execution time) 170

    Optimize native arrays for chunks

    If you need to build a NativeArray of entities to apply a structural change to, match the entity order in the array with the order of the entities in memory. The simplest way to do this is with an IJobChunk which can iterate over the chunks matching your target query. The job can iterate over the entities in the chunk in order and build a NativeArray of the entities to apply the change to.

    You can pass this NativeArray to an EntityCommandBuffer.ParallelWriter to queue up the required changes. When Unity executes the EntityCommandBuffer, entities are accessed one by one via lookups to the EntityManager. This process increases the chance of CPU cache hits because it accesses the entities in order.

    Entity command buffers and entity queries

    When an EntityQuery is passed to an EntityManager method, the method operates at a chunk level rather than on individual entities. When you pass an EntityQuery to an EntityCommandBuffer method, between the time the command is added to the EntityCommandBuffer and the time when the buffer executes its commands, the content of the chunks might change because of other structural changes.

    Use EntityQueryCaptureMode.AtPlayback to store the EntityQuery and evaluate it when the buffer is executed, which avoids executing structural changes one entity at a time.

    Enable systems to avoid structural changes

    If you want to stop a specific system from processing every entity that matches its EntityQuery, instead of removing a component from all those entities, you can disable the system itself. The best way to do this is to add or remove a component from an entity to signal if the system should be enabled. Then call the SystemState's RequireForUpdate() method in your system's OnCreate() method specifying such a component. If an entity with the component you specify exists, your system updates. If you remove the component, the system stops updating, and you only have to add or remove one component.

    You can also use the Enabled flag in SystemState to disable a system.

    Structural changes during entity creation

    Avoid adding components one at a time to construct entities at runtime. Calling EntityManager.AddComponent() creates a new archetype and moves the entity into a whole new chunk. The archetype exists for the rest of the runtime of your application and contributes to the performance overhead of the necessary calculations any time a new EntityQuery needs to calculate which EntityArchetype instances it references.

    You should create the archetype that describes the entity you want to end up with and then create an entity directly from that archetype. For example:

    // Cache this archetype if we intend to use it again later  
    var newEntityArchetype = state.EntityManager.CreateArchetype(typeof(Foo), typeof(Bar), typeof(Baz));  
    var entity = EntityManager.CreateEntity(newEntityArchetype);
    
    
    // Better yet, if you want to create lots of identical entities at the same time  
    var entities = new NativeArray<Entity>(10000, Allocator.Temp);  
    state.EntityManager.CreateEntity(newEntityArchetype, entities); 
    

    Adding or removing multiple components simultaneously

    If you need to add or remove more than one component to an entity (or a set of entities) at runtime, you can use the ComponentTypeSet struct to specify all the components to be added or removed at once, which helps to minimize the number of structural changes and redundant archetypes. The struct can be passed to EntityManager methods such as:

    • AddComponent(Entity, ComponentTypeSet)
    • AddComponent(EntityQuery, ComponentTypeSet)
    • AddComponent(SystemHandle, ComponentTypeSet)
    • Equivalent RemoveComponent() methods.

    Measuring the performance of structural changes

    Use the Structural Changes Profiler module to use this to monitor the impact of structural changes on your project's runtime performance. For more information on how to use the Profiler, refer to Profiler overview.

    Additional resources

    • Structural changes concepts
    • Use entity command buffers
    • Enableable components

    Did you find this page useful? Please give it a rating:

    Thanks for rating this page!

    Report a problem on this page

    What kind of problem would you like to report?

    • This page needs code samples
    • Code samples do not work
    • Information is missing
    • Information is incorrect
    • Information is unclear or confusing
    • There is a spelling/grammar error on this page
    • Something else

    Thanks for letting us know! This page has been marked for review based on your feedback.

    If you have time, you can provide more information to help us fix the problem faster.

    Provide more information

    You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:

    You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:

    You've told us there is information missing from this page. Please tell us more about what's missing:

    You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:

    You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:

    You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:

    You've told us this page has a problem. Please tell us more about what's wrong:

    Thank you for helping to make the Unity documentation better!

    Your feedback has been submitted as a ticket for our documentation team to review.

    We are not able to reply to every ticket submitted.

    In This Article
    • Structural change process
    • Structural changes approach comparision
    • Optimize native arrays for chunks
    • Entity command buffers and entity queries
    • Enable systems to avoid structural changes
    • Structural changes during entity creation
      • Adding or removing multiple components simultaneously
    • Measuring the performance of structural changes
    • Additional resources
    Back to top
    Copyright © 2025 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)