Help with TempJob Allocations lasting longer than 4 frames, but I dispose them?

Hi team!

I have two variables here that I declare to be TempJob. I Dispose of them, and I make sure that the job is complete the same frame. I’m doing something funky here mostly because I didn’t want a method being a billion lines, and wanted to clearly separate things for readability.

 private void runTargettingJob()
 {
     //LEAK BELOW
     var _thisFactionCalculatedTransformsTeam1 = new NativeArray<float3>(battleManager.instance.allAliveTeam1Transforms.Count(), Allocator.TempJob);
     //LEAK BELOW
     var _thisFactionCalculatedTransformsTeam2 = new NativeArray<float3>(battleManager.instance.allAliveTeam2Transforms.Count(), Allocator.TempJob);
  
     for (int i = 0; i < battleManager.instance.listAllteamsInBattle.Count; i++)
     {
          
         switch (i)
         {
             case 0:
                 **_thisFactionCalculatedTransformsTeam1 = createJob_calculateFactionPositions(battleManager.instance.listAllteamsInBattle[i].Team);**
                 break;
             case 1:
                 **_thisFactionCalculatedTransformsTeam2 = createJob_calculateFactionPositions(battleManager.instance.listAllteamsInBattle[i].Team);**
                 break;
         }
     }

     NativeArray<FindClosestsByFactionJob.DistanceIndexPair> _resultsDistanceIndexPairTeam1 = new NativeArray<FindClosestsByFactionJob.DistanceIndexPair>(battleManager.instance.allAliveTeam1Transforms.Count() * battleManager.instance.allAliveTeam2Transforms.Count(), Allocator.TempJob);
     var targettingJob = new FindClosestsByFactionJob
     {
         thisFactionPositions = _thisFactionCalculatedTransformsTeam1,
         otherFactionPositions = _thisFactionCalculatedTransformsTeam2,
         resultsDistanceIndexPair = _resultsDistanceIndexPairTeam1
     };

     JobHandle _jobHandle = targettingJob.ScheduleBatch(battleManager.instance.allAliveTeam1Transforms.Count() * battleManager.instance.allAliveTeam2Transforms.Count(), battleManager.instance.allAliveTeam2Transforms.Count());
     _jobHandle.Complete();


     _thisFactionCalculatedTransformsTeam1.Dispose();
     _thisFactionCalculatedTransformsTeam2.Dispose();

NOTE: I truncated following logic since no issues from there and it was a distraction for this topic.

This is the Method that is called on lines 14 and 17 above.

private NativeArray<float3> createJob_calculateFactionPositions(enumTeams team)
{ 

    int teamCount = 0;
    Transform[] _thisFactionPositions = null;
    switch (team)
    {
        case enumTeams.team1:
            teamCount = battleManager.instance.allAliveTeam1Transforms.Count();
            _thisFactionPositions = battleManager.instance.allAliveTeam1Transforms.ToArray();
            break;
        case enumTeams.team2:
            teamCount = battleManager.instance.allAliveTeam2Transforms.Count();
            _thisFactionPositions = battleManager.instance.allAliveTeam2Transforms.ToArray();

            break;
     
    }


    TransformAccessArray _TFA_thisFactionPositions = new TransformAccessArray(_thisFactionPositions);
    thisFactionCalculatedTransforms = new NativeArray<float3>(teamCount, Allocator.TempJob);


    var JOB_thisFactionCopyPositions = new CopyPositionsJob
    {
        positions = thisFactionCalculatedTransforms
    };


    JobHandle JOBHANDLE_thisFactionCopyPositions = JOB_thisFactionCopyPositions.Schedule(_TFA_thisFactionPositions);
    JOBHANDLE_thisFactionCopyPositions.Complete();

   
    return thisFactionCalculatedTransforms;

}

So. I return “thisFactionCalculatedTransforms”, which has an allocation of TempJob. From my understanding, the responsibility of disposing it is on the caller, so on line 14 and 17 from the first method above.

e.g: “var _thisFactionCalculatedTransformsTeam1 = new NativeArray(battleManager.instance.allAliveTeam1Transforms.Count(), Allocator.TempJob);”

So when I dispose "_thisFactionCalculatedTransformsTeam1, if should dispose the native array as well. Now, when I use stack trace in my debug log, it only mentions those above lines for the tempJob allocations going over 4 frames. I finish the job immediately using .complete(), and dispose of the arrays in the next line.

Thoughts? Any help here would be appreciated!!

Word of advice: try not to allocate and return a native collection from a method. Always create and dispose of collections in the same method, then pass in the instantiated collection in the call.

Because if you do it this way you don’t easily see the need to dispose of a collection like in the first code example. It could as well be a managed collection, it’s just not obvious from the context.

You do see that you first create a new NativeArray, and then you assign to that same variable the new NativeArray returned by createJob_calculateFactionPositions ?

This leaks your first array, and brings me back to my advice which I wrote before I found this. :grin:

2 Likes

Thank you so much!!

I just made my method huge and made sure everything is disposed - no more memory leaks! Thank you!! I’m starting to understand things a bit more now. @CodeSmile Thank you again!

1 Like