5
\$\begingroup\$

I have been reading about NativeArray, but I have to admit I do not understand it.

From the documentation:

A NativeArray exposes a buffer of native memory to managed code, making it possible to share data between managed and native without marshalling costs.

I have to admit I do not understand a word of what is being said in here.

What is the point of using it instead of normal arrays, or List? Would it be possible for someone to show me an example of how to use it, and how not to use it?

\$\endgroup\$
4
\$\begingroup\$

Native Plugins

Native arrays are relevant for communicating with a Native Plugin. Native plugins are DLL files which are compiled from code which can be written in any programming language, including "unsafe" programming languages like C++ which allow you to write very fast code by omitting some common sense safety checks. When you use native arrays, then both Unity code and DLL code can operate on the same data. Otherwise you need to copy the whole array back and forth which each function call, which can be so slow that it negates the performance gains you hoped to get form using a native plugin in the first place. Example:

// importing the function UpdateArray from myLibrary.DLL
// The function expects a memory location ("pointer") where an array of bytes can be found.
[DllImport("myLibrary")]
unsafe public static extern void UpdateArray(void* bytes);    

// declaring a native array used for communication with the DLL
private NativeArray<byte> nativeByteArray; 

// call the function from the DLL each update while passing the array by reference instead of by value
void Update() {
   unsafe {
      void* ptr = NativeArrayUnsafeUtility.GetUnsafePtr(nativeByteArray);
      UpdateArray(ptr);
   }
}

Native plugins lost a lot of relevance in the past couple years, because performance optimizations, feature additions and 3rd party assets made them unnecessary for many use-cases. Also, native plugins must be compiled separately for every platform, and not every technology makes cross-compilation as easy as Unity does. So they can be an additional hurdle for creating a cross-platform game.

But they can still be useful for some less usual scenarios, like interfacing with non-standard hardware.

Jobs system

The rather new Jobs System of Unity also makes use of native arrays (as well as their new cousins NativeList, NativeHashMap, NativeMultiHashMap and NativeQueue). The jobs system allows you to distribute expensive gameplay computations on multiple CPU cores. Native containers are mostly used for sharing data between jobs and "regular" game code. The whole system and the way it changes the way you structure the code of a Unity game is quite complex to explain just within the scope of a single answer. I recommend this Unity GDC talk for an introduction to it.

|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

I'm not an expert on native code, so I won't go into a lot of detail here, but I still think I can give you enough information to answer the question

NativeArray's can be used anywhere if you want to, but are primarily used within Unity's Job system. And their ecs system (or dots) uses it aswell (at the moment of writing, dots is still in preview, as in beta).

Unity's job system is made to be both fast and safe for multithreading. By that I mean that they do a lot of checks and add some limitations, to make sure you can't get some common errors when writing multithreaded code, as the architecture simply won't allow you to do so.

Those limitations inlude the fact that you are not allowed to reference classes inside jobs for instance (only structs). This is great as it means that you can't modify the same value in 2 jobs run at the same time, you can't accidentally do that as each job gets a copy of the value, meaning 2 jobs never get the same value in memory. On the other side, this also means that for the same reason, 2 jobs run after each other can't modify the same value.

Meet NativeContainers. They are structs that point to a piece of Native memory, meaning they can be used inside the job system and if 2 jobs are run after each other they can still access the same (native) memory. Unity then build their safety system around these NativeContainers. Meaning for instance that if you do try to write to the same memory in a NativeContainer from 2 different jobs (that can run at the same time), Unity will throw errors telling you that you are not allowed to do that and should make sure 1 of the jobs is dependent on the other to be completed first.

Another advantage is that because Unity forces you into a certain pattern with a lot of limitations, which includes using NativeCollections, Unity can optimize a lot of things for you when you enable the Burst compiler. Meaning you can write highly performant C# code. Which can be a huge difference (depending on the scenario).


There are however some rules applied to NativeArrays. These rules are basically there to ensure you use the NativeArray correctly.

  • unlike regular arrays which allow you to populate it with instances of both classes and structs, the NativeArray only allows you to popuate it with structs.
  • You have to dispose the NativeArray after you are done with it. Else you'll get memory leaks. This is because the NativeArray uses native memory instead of managed memory. For managed memory, the garbage collector makes sure data that is no longer referenced gets dealocated. This is not the case with the memory allocated for the NativeArray, you have to deallocate that memory yourself by calling Dispose.

You can find more background information about the safety system here.


As for when to use it:

I personally wouldn't advise you to use it if you are not also using the jobs system (Or dots as that uses the jobs system aswell), as the difference in performance might not even be noticable when used in regular Unity projects while the disadvantages remain. But don't take my word for it, check it yourself to be sure (in build, as Unity does a lot of extra checks in the editor that slow it down)

If you are using the jobs system, you should use them as you can't use regular arrays inside jobs.

There isn't really a point of showing you how to use a NaiveArray outside of the Job System (other then perhaps plugins already done in the other answer), and giving an example of the Job System requires me to explain a lot of the Job system itself which falls outside of the scope of this answer. So instead I would advise you see this example here, or to search for examples about unity's Job system.

|improve this answer|||||
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.