文档

Unity Engine

Unity Engine

实现自定义原生容器

Implement custom native containers.
阅读时间5 分钟最后更新于 1 个月前

要实现自定义原生容器,必须使用
NativeContainer
属性对类型进行注释。您还应该理解原生容器与安全系统集成的方式。
要实现的主要元素有二:
  • **占用跟踪:**允许 Unity 跟踪使用
    NativeContainer
    实例的被调度作业,以便检测并防止潜在冲突,例如两个作业同时对同一原生容器进行写入。
  • **泄漏跟踪:**检测未正确弃置
    NativeContainer
    的情况。在这种情况下会发生内存泄漏,此时,分配给
    NativeContainer
    的内存会在程序的整个剩余生命周期内都不可用。

实现占用跟踪

要在代码中访问占用跟踪,请使用
AtomicSafetyHandle
类。
AtomicSafetyHandle
包含对安全系统为给定原生容器存储的核心信息的引用,也是
NativeContainer
方法与安全系统交互的主要方式。也因为这一点,所有
NativeContainer
实例都必须包含一个名为
m_Safety
的
AtomicSafetyHandle
字段。
所有·
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
方法会通过一次调用同时处置
DisposeSentinel
和
AtomicSafetyHandle
。
要识别被泄漏
NativeContainer
的创建位置,可以捕获内存最初分配位置的堆栈跟踪。为此,请使用
NativeLeakDetection.Mode
属性。您还可以通过编辑器访问此属性。为此,请转到偏好设置 (Preferences) > 作业 (Jobs) > 泄漏检测级别 (Leak Detection Level),然后选择所需的级别。

嵌套原生容器

安全系统不支持在作业中使用嵌套原生容器,因为作业系统无法为大型
NativeContainer
实例中的各个单独
NativeContainer
正确配置
AtomicSafetyHandle
。
要防止调度使用嵌套原生容器的作业,请使用
SetNestedContainer
,当
NativeContainer
包含其他
NativeContainer
实例时,它会将其标记为嵌套。

安全 ID 和错误消息

安全系统会提供错误消息来指示代码不符合安全约束的情况。为让错误消息更为清晰易懂,您可以在安全系统中注册
NativeContainer
对象的名称。
要注册名称,请使用
NewStaticSafetyId
以返回可以传递给
SetStaticSafetyId
的安全 ID。安全 ID 后创建就可以在
NativeContainer
的所有实例中重复使用,因此常见的模式是将其存储在容器类的静态成员中。
还可以使用
SetCustomErrorMessage
覆盖特定安全约束违规的错误消息。

其他资源