NativeContainer
安全系统复制数据过程的缺点在于,它还会隔离每个副本中的Job结果。为了克服此限制,您需要将结果存储在一种称为NativeContainer的共享内存中(所谓共享的意思是主线程和各个Job都能访问)。
关于NativeContainer,unity有代码级的文档,https://docs.unity3d.com/ScriptReference/Unity.Collections.LowLevel.Unsafe.NativeContainerAttribute.html
建议先看本文,先了解概念,再看代码级的文档。
什么是NativeContainer?
NativeContainer是一种托管值类型,为本地内存提供相对安全的C#包装器(wrapper)。它包含一个指向非托管分配的指针。与Unity C#作业系统一起使用时,NativeContainer允许Job访问与主线程共享的数据,而不是使用副本。【个人觉得是为了性能,认同的点赞】
可用的NativeContainer类型是什么?
Unity附带了一个NativeContainer称为NativeArray的东西。您还可以NativeArray使用NativeSlice操纵,以NativeArray从特定位置到特定长度获取的子集。
注意:ECS包扩展了Unity.Collections名称空间,以包括其他类型的NativeContainer:
- NativeList-可调整大小NativeArray。
- NativeHashMap -键和值对。
- NativeMultiHashMap -每个键有多个值。
- NativeQueue- 先进先出(FIFO)队列。
- NativeContainer和安全系统
安全系统内置于所有NativeContainer类型中。它跟踪对任何对象的读写操作NativeContainer。
注意:所有关于NativeContainer类型的安全检查(例如越界检查,解除分配检查和竞争条件检查)仅在Unity Editor和Play Mode中可用。
此安全系统的一部分是DisposeSentinel和AtomicSafetyHandle。DisposeSentinel如果没有正确释放内存,检测到内存泄漏并给您一个错误。触发内存泄漏错误发生在泄漏发生很长时间之后。
使用AtomicSafetyHandle来转移NativeContainerin代码的所有权。例如,如果两个安排的Job正在写入同一作业NativeArray,则安全系统将引发异常,并显示一条清晰的错误消息,以解释原因以及如何解决该问题。当您安排(schedule)有问题的Job时,安全系统将引发此异常。
在这种情况下,您可以安排具有依赖项的Job。第一个作业可以写入NativeContainer,一旦完成执行,下一个Job就可以安全地对其进行读写NativeContainer。从主线程访问数据时,读取和写入限制也适用。安全系统确实允许多个Job并行地从同一数据读取。
默认情况下,当Job对NativeContainer有权访问时,它同时具有读和写访问权限。此配置可能会降低性能。C#Job System不允许您同时安排(schedule)两个Job,其两个Job都对同一个NativeContainer写入访问权限。
如果Job不需要写入NativeContainer,请用[ReadOnly]属性标记,如下所示:
[ReadOnly]
public NativeArray<int> input;
在上面的示例中,您可以与其他同时执行的Job只读访问NativeArray。
注意:无法防止从Job内部访问静态数据。访问静态数据会绕过所有安全系统,并可能使Unity崩溃。有关更多信息,请参见《C#Job System提示和故障排除》。
NativeContainer内存分配器
创建NativeContainer,必须指定所需的内存分配类型。分配类型取决于Job运行的时间长短。这样,您可以调整分配器以在每种情况下获得最佳性能。NativeContainer有三种用于内存分配和释放的内存分配器(Allocator)。当实例化NativeContainer,需要指定适当的一个。
- Allocator.Temp
分配最快。它用于寿命不超过一帧的分配。您不应该将NativeContainer分配使用传递Temp给作业。Dispose从方法调用返回之前,还需要先调用该方法(例如MonoBehaviour.Update或从本机代码到托管代码的任何其他回调)。 - Allocator.TempJob
分配Temp速度比慢,但比快Persistent。它用于在四个帧的生命周期内进行分配,并且是线程安全的。如果Dispose在四帧之内没有收到警告,则控制台会输出一条从本机代码生成的警告。大多数小型Job使用此分配类型。 - Allocator.Persistent
是最慢的分配,但是可以持续到您需要的时间,并且在整个应用程序的生命周期中(如果需要)。它是直接调用malloc的包装。较长的Job可以使用此分配类型。您不应在性能至关重要的地方使用Persistent
举个栗子
-
NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob);注意:上例中的数字1表示
NativeArray的大小。在这种情况下,它只有一个数组元素(因为它仅在result中存储一个数据)。
本文深入解析Unity中的NativeContainer,一种用于本地内存的托管值类型,旨在提升C#作业系统的性能。文章介绍了NativeContainer的工作原理,可用类型如NativeArray、NativeList等,以及安全系统如何确保数据访问的安全性和一致性。此外,还探讨了不同内存分配器的特点和应用场景。
三-NativeContainer&spm=1001.2101.3001.5002&articleId=105229964&d=1&t=3&u=e94333579f6b478c8b1b7ccb6e544355)
1万+

被折叠的 条评论
为什么被折叠?



