Version: Unity 6.0 (6000.0)
语言 : 中文
线程安全类型
复制 NativeContainer 结构

实现自定义原生容器

要实现自定义原生容器,必须使用 NativeContainer 属性对类型进行注释。您还应该理解原生容器与安全系统集成的方式。

要实现的主要元素有二:

  • 占用跟踪:允许 Unity 跟踪使用 NativeContainer 实例的被调度作业,以便检测并防止潜在冲突,例如两个作业同时对同一原生容器进行写入。
  • 泄漏跟踪:检测未正确弃置 NativeContainer 的情况。在这种情况下会发生内存泄漏,此时,分配给 NativeContainer 的内存会在程序的整个剩余生命周期内都不可用。

实现占用跟踪

要在代码中访问占用跟踪,请使用 AtomicSafetyHandle 类。AtomicSafetyHandle 包含对安全系统为给定原生容器存储的核心信息的引用,也是 NativeContainer 方法与安全系统交互的主要方式。也因为这一点,所有 NativeContainer 实例都必须包含一个名为 m_SafetyAtomicSafetyHandle 字段。

所有·AtomicSafetyHandle 都存储了一组标志,表示在当前上下文中可对原生容器执行的操作类型。当作业中包含 NativeContainer 实例时,作业系统会自动配置 AtomicSafetyHandle 中的标志,以反映原生容器在该作业中的使用方式。

当作业尝试通过 NativeContainer 实例进行读取时,作业系统会在读取前调用 CheckReadAndThrow 方法,以确认作业对原生容器具有读取权限。同样,当作业尝试对原生容器进行写入时,作业系统会在写入前调用 CheckWriteAndThrow,以确认作业对原生容器具有写入权限。至于分配了相同 NativeContainer 实例的两个作业,它们针对该原生容器具有单独的 AtomicSafetyHandle 对象,因此,尽管它们引用的是同一组核心信息,但它们可以持有不同的标志,以单独指示各作业对原生容器的读写权限。

实现泄漏跟踪

泄漏跟踪主要由 Unity 的原生代码实现。Unity 使用 UnsafeUtility.MallocTracked 方法来分配存储 NativeContainer 数据所需的内存,然后使用 UnsafeUtility.FreeTracked 对其进行弃置。

在 Unity 的早期版本中,提供泄漏跟踪的是 DisposeSentinel 类。Unity 会在垃圾回收器收集 DisposeSentinel 对象时报告内存泄漏。要创建 DisposeSentinel,请使用 Create 方法,该方法也会同时初始化 AtomicSafetyHandle。使用此方法时,无需初始化 AtomicSafetyHandle。当 NativeContainer 被弃置时,Dispose 方法会通过一次调用同时处置 DisposeSentinelAtomicSafetyHandle

要识别被泄漏 NativeContainer 的创建位置,可以捕获内存最初分配位置的堆栈跟踪。为此,请使用 NativeLeakDetection.Mode 属性。您还可以通过编辑器访问此属性。为此,请转到偏好设置 (Preferences) > 作业 (Jobs) > 泄漏检测级别 (Leak Detection Level),然后选择所需的级别。

嵌套原生容器

安全系统不支持在作业中使用嵌套原生容器,因为作业系统无法为大型 NativeContainer 实例中的各个单独 NativeContainer 正确配置 AtomicSafetyHandle

要防止调度使用嵌套原生容器的作业,请使用 SetNestedContainer,当 NativeContainer 包含其他 NativeContainer 实例时,它会将其标记为嵌套。

安全 ID 和错误消息

安全系统会提供错误消息来指示代码不符合安全约束的情况。为让错误消息更为清晰易懂,您可以在安全系统中注册 NativeContainer 对象的名称。

要注册名称,请使用 NewStaticSafetyId 以返回可以传递给 SetStaticSafetyId 的安全 ID。安全 ID 后创建就可以在 NativeContainer 的所有实例中重复使用,因此常见的模式是将其存储在容器类的静态成员中。

还可以使用 SetCustomErrorMessage 覆盖特定安全约束违规的错误消息。

其他资源

线程安全类型
复制 NativeContainer 结构