Best Way To Deallocate Memory For Ecs Jobs

Hi there,

I would like to know what is the preferred way to deallocate memory. In my case, these are NativeArrays which have been created per-frame then passed to various jobs to complete asynchronously. I am using
JobComponentSystem, passing the inputDeps into my first job and returning the final job of the process.

The way I look at it, I have two options:

  1. At the beginning of OnUpdate, Complete() the job and deallocate for the next execution.
  2. Create a job in the last step of the process to deallocate the memory.

Let me know if I’m on the right track or not.

Thanks

I’m leaning towards option 2. I have actually created a generic job purely to deallocate NativeArrays after I’m done using them.

NativeArray supports the [DeallocateOnJobCompletion]
this should be attached to the member of the last job accessing the array (write order) or create a seperate job for that…

[DeallocateOnJobCompletion] works fine with NativeArray, but not with others Collections (NativeList)
In one in my cases i created a persistent NativeList as a member oft the System and clear the list before reusing.

1 Like

Yep thats correct.

If you use persistent collections, you have to save the JobHandle from the last frame in a member and call Complete() before clearing it. Otherwise you will have a violation…

if you use JobComponentSystem, you don’t need to complete() by yourself.

Like Spy-Shifty said if u have to deallocate collections u should call Complete() on job that use your collection.

On JobComponentSystem you return the handle, and its complete on the end of the frame:
An exemple from my code:

protected override JobHandle OnUpdate(JobHandle inputDependencies)
{
    var nodesChunks = this.nodesQuery.CreateArchetypeChunkArray(Allocator.TempJob);
    var returnHandle = inputDependencies;
    if (nodesChunks.Length > 0)
    {
        var entityType = GetArchetypeChunkEntityType();
        var nodeType = GetArchetypeChunkComponentType<Node>(true);
        var nodeParentType = GetArchetypeChunkComponentType<NodeParent>();
        this.resetedNodes.Clear(); // <- persistent NativeList

        var filterJob = new FilterNodes()
        {
            Chunks = nodesChunks,
            ResetedNodes = this.resetedNodes,
            NodeType = nodeType,
            NodeParentType = nodeParentType,
            EntityType = entityType
        };
        var filterJobHandle = filterJob.Schedule(inputDependencies);

        var calculateJob = new CalculateNodes()
        {
            ResetedNodes = this.resetedNodes.AsDeferredJobArray(),
            EntityCommand = this.entityCommandBufferSystem.CreateCommandBuffer()
        };
        returnHandle = calculateJob.Schedule(filterJobHandle);
        this.entityCommandBufferSystem.AddJobHandleForProducer(returnHandle);
    }
    else
    {
        nodesChunks.Dispose();
    }  
    return returnHandle;
}

edit: the filter job has [DeallocateOnJobCompletion] on the chunk array.

Thanks for the great feedback everyone!

One thing I noticed - even after deallocating the memory, I still get warnings that the TempJob native containers are living longer than 4 frames. I’m not getting the errors with the stack traces, just warnings. But if the jobs are Complete()'d at the end of the frame, this shouldn’t happen right?

I have the same problem after fixing memory leaks, see Memory leak warnings spammed until Editor is restarted

yep, that’s the issue! So I’m not crazy then! I like not being crazy! :slight_smile:

I’d like to revive this thread. How is this done now? I’m still using persisting collection and clearing them before firing jobs.

[DeallocateOnJobCompletion] still works. Dispose(JobHandle inputDeps) is another option which decouples the Dispose from a job. And of course clearing a persisting collection can still be the best option if you can make that work and the collection is large.

1 Like

Does [DeallocateOnJobCompletion] work on other collections now other than NativeArray? When can Dispose(JobHandle) be called? After scheduling a job?

Nope

Think of it as a job that disposes the collection. This works for all collection types.

Yes it works after scheduling a job as long as you have your dependencies ordered correctly.