NativeArray Allocator good practices

Hello,

I have a question about how to properly assign Allocator type in NativeArray.

I noticed that in Unity examples in Update is used Allocator.TempJob then Disposed every time after Complete.

If I have job that executed in update, maybe it is better to create global NativeArray with Allocator.Persistent than create every time new native array with Allocator.TempJob ?

Thank you

I don’t think it would matter all that much. In detail TempJob should be better as you release the memory as soon as the job is done (if all systems keep persistent memory this could go up), also TempJob should be really fast to allocate. It could be better for cpu cache usage if the next system uses the previously released memory as well.

vectorized-runner Thank you for your replay.

With Allocator.Persistent, I can avoid the overhead of allocating and freeing memory on every frame.

Also the data in NativeArrays will be changed on every frame so I think cache will not help so much.

In other hand on all unity docs’s examples TempJob is used as Allocator memory type in Update.

My concern is why I need to allocate memory even very fast when I can allocate it once in Start for example ?

It’s best practice to release memory as soon as you’re done. If each of your systems allocated 100mb of memory you couldn’t use Persistent memory but you could use TempJob. In practice it might not matter.

In my case I have only four NativeArray size of 3 for iJob struct

In that case, you might want to consider using something like FixedList64Bytes and avoid using a memory allocator at all.

How much overhead did you measure? :wink:

This question is moot for as long as you don‘t implement both versions, profile them, and see which is faster in your particular scenario assuming speed is your main concern here and let‘s not forget: if it‘s faster on your target platform (ie Windows with today’s AMD Ryzen CPU) this may not even hold true and may even be the opposite for another platform (ie Mac with older Intel CPU). Lastly, when you are nearly finished it may turn out that the project is not even CPU but GPU bound.

Unless you have a general performance issue in your app and this particular code is contributing significantly to the performance issue, you are best advised to continue working on features and leave such optimization - if any - for a later time when all systems are in place and you can easily optimize 2 out of ten systems that contribute the most to runtime performance.

Spy-Master
FixedList64Bytes is good approach but in case of jobs system it has to copy whole array in job struct before execution. In the other hand NativeArrays pass only the pointer to job struct.

Thank you for your answers

Hi ! Did you come to any conclusion ? Which approach was more performant ?

It’s a really good question, too bad it didn’t get a definitive answer.
Object pooling is good practice, not instantiating if you can reuse is good practice (especially in Update), so I don’t get why in this particular instance OP gets replies such as “it doesn’t matter” etc..

My game has a field of view system, and I chose to do this using raycasts. For testing purposes I increased to about 5000 raycasts per frame, I tried both approaches (2 NativeArrays, 8k each, for commands and results):

  • in Start, allocating persistent, disposing them in OnDispose;
  • in Update, allocating TempJob and disposing every frame
    I didn’t see any impact on performance, my fps on a potato pc on battery (the only measure I have which isn’t great but better than nothing) was basically the same in both cases.

Since it doesn’t seem to matter, I went with the persistent way which makes more sense to me. Don’t do what doesn’t need to be done.

A reused persistent allocation will be cheaper, but it’s going to be difficult to notice the impact, especially if it’s just a single allocation.

Don’t measure FPS. Use the profiler to find out the actual overhead of allocating memory.

Another thing to consider is that the allicators are almost certainly pooling internally themselves. It’s kinda “video game c++ rule #1: use your own allocators for high performance memory management needs”. Hence, the reason they have difference classes of allocators to begin with.