네이티브 컨테이너는 값 유형이므로 변수에 할당되면 Unity는 네이티브 컨테이너의 데이터가 저장되는 위치(AtomicSafetyHandle 포함)에 대한 포인터를 포함하는 NativeContainer 구조를 복사합니다. NativeContainer의 전체 내용을 복사하지는 않습니다.
이 시나리오는 모두 동일한 메모리 영역을 참조하고 모두 동일한 중앙 레코드를 참조하는 AtomicSafetyHandle 오브젝트를 포함한 NativeContainer 구조의 사본이 여러 개 있을 수 있음을 의미합니다.
위의 다이어그램은 모두 동일한 실제 컨테이너를 나타내는 NativeArray 구조의 세 가지 사본을 보여 줍니다. 각 사본은 저장된 동일한 데이터 및 원본 NativeArray와 동일한 안전 데이터를 가리킵니다. 그러나 각 NativeArray의 사본에는 해당 사본으로 수행할 수 있는 잡을 나타내는 다른 플래그가 있습니다. 안전 데이터에 대한 포인터와 플래그가 결합되어 AtomicSafetyHandle을 구성합니다.
NativeContainer가 폐기되는 경우, 모든 NativeContainer 구조의 사본은 원본 NativeContainer가 무효임을 인식해야 합니다. 원본 NativeContainer의 폐기란 NativeContainer의 데이터를 저장하는 데 사용된 메모리 블록이 할당 해제되었음을 의미합니다. 이 경우 각 NativeContainer 사본에 저장된 데이터에 대한 포인터가 유효하지 않으며 사용 시 액세스 위반이 발생할 수 있습니다.
또한 AtomicSafetyHandle은 NativeContainer 인스턴스에 대해 무효화되는 중앙 기록을 가리킵니다. 하지만 안전 시스템은 중앙 레코드에 대한 메모리를 할당 해제하지 않으므로 액세스 위반의 위험을 방지합니다.
대신 각 기록에는 버전 번호가 포함됩니다. 해당 기록을 참조하는 각 AtomicSafetyHandle 내에 버전 번호 사본이 저장됩니다. NativeContainer가 폐기되면 Unity는 Release()를 호출하여 중앙 기록의 버전 번호를 증가시킵니다. 그런 다음 다른 NativeContainer 인스턴스에 대해 기록을 재사용할 수 있습니다.
나머지 AtomicSafetyHandle은 각각 저장된 버전 번호와 중앙 기록의 버전 번호를 비교하여 NativeContainer가 폐기되었는지 테스트합니다. Unity는 CheckReadAndThrow 및 CheckWriteAndThrow와 같은 메서드 호출의 일환으로 이 테스트를 자동으로 수행합니다.
동적 네이티브 컨테이너는 NativeList<T>(Collections 패키지에서 사용 가능)와 같이 요소를 계속 추가할 수 있는 변수 크기가 있는 컨테이너입니다. 이는 고정된 크기이며 변경할 수 없는 NativeArray<T>와 같은 정적 네이티브 컨테이너와 다릅니다.
동적 네이티브 컨테이너를 사용하는 경우 뷰라는 다른 인터페이스를 통해 해당 데이터에 직접 액세스할 수도 있습니다. 뷰를 사용하면 데이터를 복사하거나 소유권을 취하지 않고도 NativeContainer 오브젝트의 데이터에 별칭을 지정할 수 있습니다. 뷰의 예로는 네이티브 컨테이너의 데이터에 요소별로 액세스하는 데 사용할 수 있는 열거자 오브젝트와 NativeList를 NativeArray처럼 취급하는 데 사용할 수 있는 NativeList<T>.AsArray와 같은 메서드가 있습니다.
뷰는 일반적으로 동적 네이티브 컨테이너의 크기가 변경되는 경우 스레드에 안전하지 않습니다. 네이티브 컨테이너의 크기가 변경되면 Unity는 데이터가 메모리에 저장되는 위치를 재배치하므로 뷰에서 저장하는 모든 포인터가 무효화되기 때문입니다.
동적 네이티브 컨테이너의 크기가 변경되는 상황을 지원하기 위해 안전 시스템은 AtomicSafetyHandle에 보조 버전 번호를 포함합니다. 이 메커니즘은 버전 지정 메커니즘과 유사하지만, 중앙 기록에 저장된 두 번째 버전 번호를 사용하며 이는 첫 번째 버전 번호와 독립적으로 증분할 수 있습니다.
보조 버전 번호를 사용하려면 UseSecondaryVersion을 사용하여 NativeContainer에 저장된 데이터의 뷰를 설정할 수 있습니다. 네이티브 컨테이너의 크기를 변경하거나 기존 뷰를 무효화하는 작업의 경우 CheckWriteAndThrow 대신 CheckWriteAndBumpSecondaryVersion을 사용합니다. 또한 네이티브 컨테이너에 쓰는 잡이 예약될 때마다 뷰가 자동으로 무효화되도록 NativeContainer의 SetBumpSecondaryVersionOnScheduleWrite도 설정해야 합니다.
뷰를 생성하고 AtomicSafetyHandle을 뷰에 복사할 때 CheckGetSecondaryDataPointerAndThrow를 사용하여 네이티브 컨테이너의 메모리에 대한 포인터를 뷰에 복사할 수 있는지 확인합니다.
임시 네이티브 컨테이너로 작업할 때 사용할 수 있는 두 가지 특수 핸들이 있습니다.
GetTempMemoryHandle: Allocator.Temp로 할당된 네이티브 컨테이너에서 사용할 수 있는 AtomicSafetyHandle을 반환합니다. 현재 임시 메모리 범위가 종료되면 Unity는 이 핸들을 자동으로 무효화하므로 직접 해제할 필요가 없습니다. 특정 AtomicSafetyHandle이 GetTempMemoryHandle에서 반환한 핸들인지 테스트하려면 IsTempMemoryHandle을 사용합니다.GetTempUnsafePtrSliceHandle: 안전하지 않은 메모리에서 지원되는 임시 네이티브 컨테이너에 사용 가능한 전역 핸들을 반환합니다. 예를 들면 스택 메모리로 구성된 NativeSlice가 있습니다. 이 핸들을 사용하는 컨테이너는 잡에 전달할 수 없습니다.