Introduction to unmanaged collections
Introduction to unmanaged collections.
Read time 3 minutesLast updated 7 days ago
The namespace provides unmanaged C# containers that you can use in jobs and Burst-compiled code. The collections in this namespace fall into the following categories:
Unity.Collections- Collection types with safety checks to ensure they're used in a thread-safe way and properly disposed of. These types are in the namespace and their names start with
Unity.Collections.Native - Collection types without safety checks. These types are in the namespace and their names start with
Unity.Collections.LowLevel.Unsafe.Unsafe
The remaining collection types that don't fit into these categories aren't allocated and don't contain any pointers. These types only contain small amounts of data, and their disposal and thread safety aren't a concern.
Safety handles and checks
NativeAtomicSafetyHandleUnsafeUnsafeUnsafeListUnsafePtrListCollectionHelper.CheckIndexInRangeNativeChecks are always enabled in the Editor, and in Player builds with the Checked managed code variant. The only way to make these checks fully zero-cost is to run in a Player build that doesn't include safety checks.
It's important to understand that disabling safety checks in the Editor doesn't compile out these checks:
- The Burst menu option to disable safety checks has a specific and limited effect: when a subset of checks are called from Burst-compiled code, they're compiled out. If Burst is disabled, or if a method runs outside of Burst for any other reason, this option has no effect on that code.
- Disabling the jobs debugger disables a subset of jobs debugger threading checks, but doesn't reduce the overall cost of checks to zero.
Neither of these options reduces the cost of checks overall to zero.
Native versus Unsafe collections
It's best practice to use collections over the equivalents, because the safety handles catch access, disposal, and job-dependency errors. However, it's sometimes necessary to use the equivalents, because collection types can't contain other collections. This limitation comes from how Unity implements the safety handles. For example, if you want a list of lists, you can use either or , but you can't use .
NativeUnsafeUnsafeNativeNativeNativeNativeList<UnsafeList<T>>UnsafeList<UnsafeList<T>>NativeList<NativeList<T>>Most collections are implemented as wrappers of their counterparts. For example, is made up of an plus the handles that the safety checks use. Because of this wrapping, a type is not free even when checks are compiled out: the internal collection introduces an extra pointer indirection, which adds cost by itself even in unchecked Player builds.
NativeUnsafeNativeListUnsafeListNativeUnsafeSeveral types have equivalents, for example, has , and has .
NativeUnsafeNativeListUnsafeListNativeHashMapUnsafeHashMapThe following table summarizes the comparative safety features of and collection types:
NativeUnsafeBehavior | Native | Unsafe |
|---|---|---|
| Job safety checks | Yes | No |
| Index bound checks | Yes | Partially (when safety checks are enabled) |
| Containing behavior | Can only contain | Can contain either |
Passing collections by value
The way changes are reflected when you pass a collection by value differs between collection types:
- If you pass a by value and either write into the data or resize the list, the changes are reflected in the caller's copy of the list.
NativeList - If you pass an by value and write into the data, those writes are reflected in the caller's version. However, if you resize the list, that change is not reflected in the caller's copy, and moreover all subsequent writes are not reflected either.
UnsafeList - If you pass a by value, nothing is reflected in the caller's copy, because the entire contents are copied when you pass it.
FixedList