JobTempAlloc has allocations that are more than 4 frames old

Hello,

I have a job that copies the positions of the tanks and another job that consumes them to check the distance, for this I use a NativeArray but it shows me the following warning and I don’t understand the reason.

Internal: JobTempAlloc has allocations that are more than 4 frames old - this is not allowed and likely a leak
using Components.Tags;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;

namespace Systems
{
    [UpdateInGroup(typeof(SimulationSystemGroup))]
    public class BulletVsTankCollisionSystem : JobComponentSystem
    {
        private EntityQuery _tankGroup;
        private EntityQuery _bulletGroup;
       
        private BeginInitializationEntityCommandBufferSystem _commandBufferSystem;
       
        protected override void OnCreate()
        {
            _tankGroup = GetEntityQuery(new EntityQueryDesc
            {
                All = new[] {ComponentType.ReadOnly<Tank>(), ComponentType.ReadOnly<Translation>()},
            });
           
            _bulletGroup = GetEntityQuery(new EntityQueryDesc
            {
                All = new[] {ComponentType.ReadOnly<Bullet>(), ComponentType.ReadOnly<Translation>()},
            });
           
            _commandBufferSystem = World.GetOrCreateSystem<BeginInitializationEntityCommandBufferSystem>();
        }

        [BurstCompile]
        private struct CopyPositions : IJobForEachWithEntity<Translation>
        {
            public NativeArray<float3> Positions;
            public NativeArray<Entity> Entities;

            public void Execute(Entity entity, int index, [ReadOnly] ref Translation localToWorld)
            {
                Positions[index] = localToWorld.Value;
                Entities[index] = entity;
            }
        }

        [BurstCompile]
        [RequireComponentTag(typeof(Bullet))]
        private struct CheckDistanceJob : IJobForEachWithEntity<Translation>
        {
            [DeallocateOnJobCompletion] [ReadOnly] public NativeArray<float3> CopyTankPositions;
            [DeallocateOnJobCompletion] [ReadOnly] public NativeArray<Entity> CopyTankEntities;
            [ReadOnly] public EntityCommandBuffer CommandBuffer;

            public void Execute(
                Entity entity,
                int index,
                [ReadOnly] ref Translation translation
            )
            {
                // TODO: Check distance, add damage...
                CommandBuffer.DestroyEntity(entity);
            }
        }

        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            var tankCount = _tankGroup.CalculateLength();
            var copyTankPositions = new NativeArray<float3>(tankCount, Allocator.TempJob,
                NativeArrayOptions.UninitializedMemory);
            var copyTankEntities = new NativeArray<Entity>(tankCount, Allocator.TempJob,
                NativeArrayOptions.UninitializedMemory);

            var copyTankPositionsJob = new CopyPositions
            {
                Positions = copyTankPositions,
                Entities = copyTankEntities
            };
            var copyTankPositionsJobHandle = copyTankPositionsJob.Schedule(_tankGroup, inputDeps);

            var checkDistanceJob = new CheckDistanceJob
            {
                CopyTankPositions = copyTankPositions,
                CopyTankEntities = copyTankEntities,
                CommandBuffer = _commandBufferSystem.CreateCommandBuffer()
            };
           
            var checkDistanceJobHandle = checkDistanceJob.Schedule(_bulletGroup, copyTankPositionsJobHandle);

            _commandBufferSystem.AddJobHandleForProducer(checkDistanceJobHandle);
         
            return checkDistanceJobHandle;
        }
    }
}

How can I solve that? Is there a better way to do it?

Thanks in advance.

Is it maybe that your deallocations are in the CheckDistanceJob but if there’s no bullets, that job is not going to run?
I don’t know what ecs does behind the scenes if the _bulletGroup is empty and whether it’ll still DeallocateOnJobCompletion even if the job doesn’t run.

Maybe first check if _bulletGroup.CalculateLength() == 0 and if so just exit OnUpdate. Presumably there’s no point running the tankPositions job and allocating arrays if there’s no bullets?
Otherwise you can try tack on a third job that runs regardless to deallocate the arrays, or create the arrays as instance members of BulletVsTankCollisionSystem and dispose them at the start of OnUpdate each frame.

You could also try using RequireForUpdate protected method on your 2 EQ on OnCreate so that it must either run until the deallocation or not update at all.

Ah I knew I forgot one. :slight_smile:
Yes RequireForUpdate in OnCreate is best option.

protected override void OnCreate() {
    ...
    RequireForUpdate(_tankGroup);
    RequireForUpdate(_bulletGroup);
}
1 Like

Both one and the other work, I will use RequireForUpdate :smile:

Thank you very much.

1 Like

I got this all the time, and before banging your head looking for bugs, restart Unity.
Usually they are leaking, not me.

6 Likes

I’m really glad to have read and tried this. Seems that leaving Unity open and going suspension mode it’s “not supported” by Unity itself.

Is this correct?