네이티브 컨테이너는 값 타입이므로 변수에 할당되면 Unity는 네이티브 컨테이너의 데이터가 저장된 위치에 대한 포인터가 포함된 NativeContainer
구조체를 복사하며, 여기에는 AtomicSafetyHandle
등이 포함됩니다.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>
(컬렉션 패키지에서 사용 가능)처럼, 요소를 계속 추가할 수 있는 가변 크기를 가진 컨테이너입니다.이는 변경할 수 없는 고정 크기를 가진 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
를 들 수 있습니다.이 핸들을 사용하는 컨테이너는 잡으로 전달할 수 없습니다.