Error looping through native array

Hello the code at line 39 41 & 43 give me these errors
the code runs fine in the first frame but units that have a spawntime above 0 dont spawn
the code also runs fine when the 39 loop that contains 41 & 43 is removed
how do i fix this?

(Errors)

InvalidOperationException: The previously scheduled job SpawnerSystem:OnUpdate_LambdaJob0 writes to the Unity.Collections.NativeArray1[Spawner] OnUpdate_LambdaJob0.JobData.SpawnerArray. You must call JobHandle.Complete() on the job SpawnerSystem:OnUpdate_LambdaJob0, before you can deallocate the Unity.Collections.NativeArray1[Spawner] safely.
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckDeallocateAndThrow (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at <88f69663e9a64d00b2091dd8dfd4d38f>:0)
Unity.Collections.LowLevel.Unsafe.DisposeSentinel.Dispose (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle& safety, Unity.Collections.LowLevel.Unsafe.DisposeSentinel& sentinel) (at <88f69663e9a64d00b2091dd8dfd4d38f>:0)
Unity.Collections.NativeArray`1[T].Dispose () (at <88f69663e9a64d00b2091dd8dfd4d38f>:0)
SpawnerSystem.OnUpdate () (at Assets/SpawnerSystem.cs:64)
Unity.Entities.SystemBase.Update () (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/SystemBase.cs:412)
Unity.Entities.ComponentSystemGroup.UpdateAllSystems () (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ComponentSystemGroup.cs:472)
UnityEngine.Debug:LogException(Exception)
Unity.Debug:LogException(Exception) (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/Stubs/Unity/Debug.cs:19)
Unity.Entities.ComponentSystemGroup:UpdateAllSystems() (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ComponentSystemGroup.cs:477)
Unity.Entities.ComponentSystemGroup:OnUpdate() (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ComponentSystemGroup.cs:417)
Unity.Entities.ComponentSystem:Update() (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ComponentSystem.cs:114)
Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ScriptBehaviourUpdateOrder.cs:333)

ArgumentException: The previously scheduled job SpawnerSystem:OnUpdate_LambdaJob0 writes to the Unity.Entities.EntityCommandBuffer OnUpdate_LambdaJob0.JobData.ecb. You must call JobHandle.Complete() on the job SpawnerSystem:OnUpdate_LambdaJob0, before you can write to the Unity.Entities.EntityCommandBuffer safely.
EntityCommandBuffer was recorded in SpawnerSystem and played back in Unity.Entities.BeginSimulationEntityCommandBufferSystem.
at (wrapper managed-to-native) Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrowNoEarlyOut_Injected(Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle&)
at Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrowNoEarlyOut (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) [0x00000] in <88f69663e9a64d00b2091dd8dfd4d38f>:0
at Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrow (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) [0x00021] in <88f69663e9a64d00b2091dd8dfd4d38f>:0
at Unity.Entities.EntityCommandBuffer.EnforceSingleThreadOwnership () [0x0001a] in C:\Games\game making\Unity\Projects\My project\Library\PackageCache\com.unity.entities@0.17.0-preview.42\Unity.Entities\EntityCommandBuffer.cs:1100
at Unity.Entities.EntityCommandBuffer.PlaybackInternal (Unity.Entities.EntityDataAccess* mgr) [0x00001] in C:\Games\game making\Unity\Projects\My project\Library\PackageCache\com.unity.entities@0.17.0-preview.42\Unity.Entities\EntityCommandBuffer.cs:1711
at Unity.Entities.EntityCommandBuffer.Playback (Unity.Entities.EntityManager mgr) [0x00001] in C:\Games\game making\Unity\Projects\My project\Library\PackageCache\com.unity.entities@0.17.0-preview.42\Unity.Entities\EntityCommandBuffer.cs:1696
at Unity.Entities.EntityCommandBufferSystem.FlushPendingBuffers (System.Boolean playBack) [0x00097] in C:\Games\game making\Unity\Projects\My project\Library\PackageCache\com.unity.entities@0.17.0-preview.42\Unity.Entities\EntityCommandBufferSystem.cs:227

Unity.Entities.EntityCommandBufferSystem.FlushPendingBuffers (System.Boolean playBack) (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/EntityCommandBufferSystem.cs:294)
Unity.Entities.EntityCommandBufferSystem.OnUpdate () (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/EntityCommandBufferSystem.cs:192)
Unity.Entities.ComponentSystem.Update () (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ComponentSystem.cs:114)
Unity.Entities.ComponentSystemGroup.UpdateAllSystems () (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ComponentSystemGroup.cs:472)
UnityEngine.Debug:LogException(Exception)
Unity.Debug:LogException(Exception) (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/Stubs/Unity/Debug.cs:19)
Unity.Entities.ComponentSystemGroup:UpdateAllSystems() (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ComponentSystemGroup.cs:477)
Unity.Entities.ComponentSystemGroup:OnUpdate() (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ComponentSystemGroup.cs:417)
Unity.Entities.ComponentSystem:Update() (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ComponentSystem.cs:114)
Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at Library/PackageCache/com.unity.entities@0.17.0-preview.42/Unity.Entities/ScriptBehaviourUpdateOrder.cs:333)

Missing Profiler.EndSample (BeginSample and EndSample count must match): SpawnerSystem
Previous 5 samples:
MemoryManager.FallbackDeallocation
EntityCommandBuffer.Playback
GC.Alloc
Mono.JIT
GC.Alloc
In the scope:
SpawnerSystem
Default World Unity.Entities.BeginSimulationEntityCommandBufferSystem
Default World Unity.Entities.SimulationSystemGroup
UnityEngine.CoreModule.dll!::UpdateFunction.Invoke()
SimulationSystemGroup

A Native Collection has not been disposed, resulting in a memory leak. Enable Full StackTraces to get more details.

(Code)

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;

public class SpawnerSystem : SystemBase
{
    BeginSimulationEntityCommandBufferSystem bsecbs;

    protected override void OnCreate()
    {
        base.OnCreate();
        bsecbs = World.GetOrCreateSystem<BeginSimulationEntityCommandBufferSystem>();
    }

    protected override void OnUpdate()
    {
        float time = (float)Time.ElapsedTime;
        Random rng = new Random(1);

        EntityCommandBuffer.ParallelWriter ecb = bsecbs.CreateCommandBuffer().AsParallelWriter();

        EntityQuery query = GetEntityQuery(ComponentType.ReadOnly<Spawner>(), ComponentType.ReadOnly<Translation>());
        NativeArray<Spawner> SpawnerArray = query.ToComponentDataArray<Spawner>(Allocator.TempJob);
        NativeArray<Translation> TranslationArray = query.ToComponentDataArray<Translation>(Allocator.TempJob);

        Entities.ForEach((int entityInQueryIndex,Entity entity, in UnitSpawnInfo usi) => 
        {
            //check if time to spawn
            if (usi.Time <= time)
            {

                //Get Spawner Position
                float3 SpawnerPos = new float3();
                int counter = 0;
                for (int s = 0; s < SpawnerArray.Length; s++)
                {
                    if (SpawnerArray[s].ID == usi.SpawnerID)
                    {
                        SpawnerPos = TranslationArray[counter].Value;
                        break;
                    }
                    counter++;
                }

                //Spawn Units
                for (int i =0; i < usi.Count; i++)
                {
                    Entity NewSpawn = ecb.Instantiate(entityInQueryIndex,usi.Unit);

                    Translation SpawnPoint = new Translation();
                    SpawnPoint.Value += SpawnerPos + new float3(rng.NextFloat(-1f, 1f), 0, rng.NextFloat(-1f, 1f));
                   
                    ecb.SetComponent(entityInQueryIndex,NewSpawn,SpawnPoint);
                }

                //destroy spawninfo entity
                ecb.DestroyEntity(entityInQueryIndex, entity);
            }
        }).ScheduleParallel();

        SpawnerArray.Dispose();
        TranslationArray.Dispose();
        bsecbs.AddJobHandleForProducer(Dependency);
    }
}

Looks to me like you’re trying to Dispose() those NativeArrays before the job that uses them is completed.

1 Like

but i only call the dispose method after the job is scheduled
adding them at the very bottom under the jobhandle producer doesnt change it either.

You do it after the job is scheduled but not after the job is completed. The job is still running, you can’t dispose its arrays while it’s running.

2 Likes

ScheduleParallel will schedule the job asynchronously. So when the ScheduleParallel call returns, the jobs are most likely not completed yet. That’s why the docs say that ScheduleParallel returns a JobHandle which can later be used as a dependency for another job or to ensure completion on the main thread. You did not do that. You did not wait for the jobs to finish. You just disposed the arrays your jobs depend on while they’re running.

If you want to synchronously finish the jobs, you have to call Complete on the job handle that is returned by ScheduleParallel before you dispose the arrays. If you want to finish the jobs asynchronously you have to delay the disposing of the array, probably through another job that depends on your current.

I haven’t really used Unity’s job system, so I can’t really give advice what may be the best approach. Though just reading the documentation tells us that what you’re currently doing can’t really work.

2 Likes

okey thanks i added CompleteDependency() after jobhandleforproducer and the dispose methods after that.
works now :slight_smile:

        bsecbs.AddJobHandleForProducer(Dependency);
        CompleteDependency();
        SpawnerArray.Dispose();
        TranslationArray.Dispose();
1 Like