isbits Union Optimizations

줄리아에서 Array 타입은 "비트" 값과 힙에 할당된 "박스" 값을 모두 포함합니다. 구분은 값 자체가 인라인으로 저장되는지(배열의 직접 할당된 메모리 내에) 아니면 배열의 메모리가 단순히 다른 곳에 할당된 객체에 대한 포인터의 모음인지에 따라 다릅니다. 성능 측면에서 인라인 값을 접근하는 것은 실제 값에 대한 포인터를 따라가는 것보다 분명한 이점이 있습니다. "isbits"의 정의는 일반적으로 고정된 결정적 크기를 가진 모든 줄리아 타입을 의미하며, 이는 "포인터" 필드가 없음을 의미합니다. ?isbitstype을 참조하세요.

Julia는 Union 타입을 지원하며, 이는 문자 그대로 타입 집합의 합집합입니다. 사용자 정의 Union 타입 정의는 명시적 하위 타입 관계(즉, 명명된 타입 시스템)를 "가로지르는" 애플리케이션에 매우 유용할 수 있으며, 이러한 서로 관련이 없는 타입 집합에 대해 메서드나 기능을 정의할 수 있습니다. 그러나 컴파일러의 도전 과제는 이러한 Union 타입을 어떻게 처리할 것인지 결정하는 것입니다. 단순한 접근 방식(실제로 Julia가 0.7 이전에 사용했던 방식)은 "상자"를 만들고 그 상자 안에 실제 값에 대한 포인터를 두는 것입니다. 이는 이전에 언급한 "박스화된" 값과 유사합니다. 그러나 이는 불행한 일입니다. 왜냐하면 UInt8, Int32, Float64 등과 같은 많은 작은 원시 "비트" 타입들이 이 "상자" 안에 직접 들어갈 수 있기 때문입니다. 값 접근을 위한 간접 참조가 필요하지 않습니다. 0.7 기준으로 Julia가 이 최적화를 활용할 수 있는 두 가지 주요 방법은 타입의 isbits Union 필드와 isbits Union 배열입니다.

isbits Union Structs

줄리아는 이제 "isbits Union" 필드가 있는 타입(mutable struct, struct 등)을 인라인으로 저장하는 최적화를 포함합니다. 이는 유니온 타입의 "인라인 크기"를 결정함으로써 이루어집니다(예: Union{UInt8, Int16}는 두 바이트의 크기를 가지며, 이는 가장 큰 유니온 타입 Int16에 필요한 크기를 나타냅니다). 또한, "유니온 바이트"의 인라인에 저장된 실제 값의 타입을 신호하는 값인 추가 "타입 태그 바이트"(UInt8)를 할당합니다. 타입 태그 바이트 값은 유니온 타입의 타입 순서에서 실제 값의 타입의 인덱스입니다. 예를 들어, 타입 Union{Nothing, UInt8, Int16}의 필드에 대해 0x02의 타입 태그 값은 구조체의 메모리에서 필드의 16비트에 Int16 값이 저장되어 있음을 나타냅니다. 0x01 값은 필드의 메모리의 첫 8비트에 UInt8 값이 저장되어 있음을 나타냅니다. 마지막으로, 0x00 값은 이 필드에 대해 nothing 값이 반환될 것임을 신호합니다. 비록 단일 타입 인스턴스를 가진 단일톤 타입으로서 기술적으로 크기가 0이지만 말입니다. 타입의 유니온 필드에 대한 타입 태그 바이트는 필드의 계산된 유니온 메모리 바로 뒤에 저장됩니다.

isbits Union Memory

줄리아는 이제 "isbits Union" 값을 메모리에 인라인으로 저장할 수 있으며, 이는 간접 박스가 필요하지 않습니다. 이 최적화는 실제 데이터의 바이트와 함께 각 요소당 하나의 바이트인 추가 "타입 태그 메모리"를 저장함으로써 이루어집니다. 이 타입 태그 메모리는 타입 필드 케이스와 동일한 기능을 수행합니다: 그 값은 실제로 저장된 Union 값의 타입을 신호합니다. "타입 태그 메모리"는 일반 데이터 공간 바로 뒤에 위치합니다. 따라서 isbits Union 배열의 타입 태그 바이트에 접근하는 공식은 a->data + a->length * a->elsize입니다.