0Pricing
Swift Academy · 강의

MemoryLayout과 정렬

형식의 크기, 간격, 정렬을 검사합니다.

MemoryLayout과 정렬은(는) CoddyKit의 무료 Swift Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Swift Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

메모리 레이아웃이 중요한 이유

안전하지 않은 Swift를 사용하거나 C와 연결할 때는 값이 메모리에 어떻게 배치되는지 알아야 합니다. Swift에서는 원시 바이트에 직접 접근하지 않고도 MemoryLayout<T>을 사용해 이를 확인할 수 있습니다.

이를 통해 세 가지를 알 수 있습니다. 값의 크기, 배열에서 값 사이의 간격, 그리고 값이 시작해야 하는 주소 경계입니다.

// MemoryLayout works on any type
print(MemoryLayout<Int>.size)       // 8 on 64-bit
print(MemoryLayout<Bool>.size)      // 1
print(MemoryLayout<Double>.size)    // 8

size — 실제 저장 공간

MemoryLayout<T>.size는 값의 유효한 데이터가 차지하는 바이트 수입니다. 배열의 요소 사이에 있을 수 있는 뒤쪽 패딩은 포함하지 않습니다.

단일 값이 보유한 의미 있는 바이트 수를 알고 싶을 때 size를 사용합니다.

struct Point {
    var x: Int8   // 1 byte
    var y: Int64  // 8 bytes
}

print(MemoryLayout<Point>.size)   // 16 (not 9 — padding!)

stride — 배열에서의 간격

stride는 값이 연속 배열에 배치될 때 한 요소의 시작 지점과 다음 요소의 시작 지점 사이의 바이트 거리입니다. 이는 size를 alignment 단위로 올림한 값과 같습니다.

버퍼를 직접 할당할 때는 size가 아니라 항상 stride를 곱합니다.

print(MemoryLayout<Point>.stride) // 16
print(MemoryLayout<Int8>.stride)  // 1

// Buffer for 10 Points needs:
let bytes = 10 * MemoryLayout<Point>.stride // 160

alignment — 주소 경계

alignment는 값이 시작해야 하는 바이트 경계입니다. Int64는 alignment가 8이므로 8로 나누어떨어지는 주소에서 시작해야 합니다. 컴파일러는 이를 지키기 위해 패딩을 삽입합니다.

구조체의 alignment는 멤버 중 가장 큰 alignment입니다.

print(MemoryLayout<Int8>.alignment)   // 1
print(MemoryLayout<Int64>.alignment)  // 8
print(MemoryLayout<Point>.alignment)  // 8

size와 stride의 차이

많은 유형에서는 size == stride이지만, 패딩이 있으면 둘은 달라집니다. 다음 요소가 8바이트 정렬을 따라야 하므로 구조체의 size는 9인데 stride는 16일 수 있습니다.

경험 법칙: 단일 값은 size를 기준으로 이해하고, 컬렉션은 stride를 기준으로 이해하십시오.

struct Mixed {
    var flag: Bool   // 1
    var value: Int   // 8
}
print(MemoryLayout<Mixed>.size)   // 16
print(MemoryLayout<Mixed>.stride) // 16

필드 오프셋

구조체에서는 키 경로와 함께 MemoryLayout<T>.offset(of:)를 사용하여 각 저장 프로퍼티가 시작 지점을 기준으로 어디에 있는지 확인할 수 있습니다. C 구조체와 동일하게 데이터를 배치할 때 필수적입니다.

struct Header {
    var magic: UInt32  // offset 0
    var length: UInt64 // offset 8 (padded)
}

print(MemoryLayout<Header>.offset(of: \Header.magic) ?? -1)  // 0
print(MemoryLayout<Header>.offset(of: \Header.length) ?? -1) // 8

공간 절약을 위한 순서 변경

alignment 때문에 저장 프로퍼티의 순서가 크기에 영향을 줍니다. 더 큰 필드를 앞에 배치하거나 크기별로 그룹화하면 구조체 크기를 줄일 수 있습니다. 낭비되는 바이트가 누적되는 큰 배열에서는 특히 중요합니다.

struct Wasteful { var a: Int8; var b: Int64; var c: Int8 } // size 24
struct Tight    { var b: Int64; var a: Int8; var c: Int8 } // size 16

print(MemoryLayout<Wasteful>.size)
print(MemoryLayout<Tight>.size)

참조의 메모리 배치

클래스 인스턴스는 힙에 할당되므로, 클래스 참조를 보유한 변수는 단지 pointer일 뿐입니다. 객체의 크기와 관계없이 MemoryLayout.size는 pointer 크기인 8바이트입니다.

구조체와 같은 값 유형은 내용을 인라인으로 저장하고, 참조 유형은 pointer만 저장합니다.

class Big { var data = [Int](repeating: 0, count: 1000) }

print(MemoryLayout<Big>.size) // 8 — just the reference

옵셔널과 열거형

옵셔널은 일반적으로 태그를 저장하기 위해 1바이트를 추가하지만, Swift는 reference 옵셔널에서 null pointer를 재사용하도록 최적화하므로 String?은 String과 크기가 같을 수 있습니다.

연관 값이 있는 열거형은 가장 큰 항목과 판별자를 저장할 수 있는 크기로 정해집니다.

print(MemoryLayout<Int?>.size)    // 9
print(MemoryLayout<String>.size)  // 16
print(MemoryLayout<String?>.size) // 16 — no extra byte

인스턴스와 함께 of: 사용하기

모든 멤버(size, stride, alignment)에는 인스턴스 기반 형식인 MemoryLayout.size(ofValue:)도 있습니다. 유형을 명시하기 어렵거나 유형이 추론될 때 유용합니다.

let tuple = (UInt8(1), UInt64(2))
print(MemoryLayout.size(ofValue: tuple))      // 16
print(MemoryLayout.stride(ofValue: tuple))    // 16
print(MemoryLayout.alignment(ofValue: tuple)) // 8

올바른 레이아웃으로 할당하기

원시 메모리를 할당할 때는 바이트 수와 alignment를 모두 전달해야 합니다. 이 값을 MemoryLayout에서 가져오면 숫자를 직접 지정하지 않아도 아키텍처에 관계없이 올바르게 처리됩니다.

let count = 4
let capacity = count * MemoryLayout<Int>.stride
let align = MemoryLayout<Int>.alignment

let raw = UnsafeMutableRawPointer.allocate(
    byteCount: capacity, alignment: align)
defer { raw.deallocate() }

빠른 확인

size와 stride의 차이에 대한 이해도를 확인해 보십시오.

요약

메모리 레이아웃의 세 가지 핵심 요소를 학습했습니다:

  • size — 단일 값의 의미 있는 바이트
  • stride — 배열 요소 사이의 간격(할당에 사용)
  • alignment — 필요한 시작 경계

필드 위치를 위한 offset(of:), 프로퍼티 순서가 크기에 미치는 영향, 참조가 pointer 크기일 뿐이라는 점도 살펴보았습니다. 이러한 도구를 사용하면 원시 메모리를 안전하게 할당하고 해석할 수 있습니다.

자주 묻는 질문

“MemoryLayout과 정렬” 강의는 무료인가요?

네 — “MemoryLayout과 정렬” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Swift Academy 강의 전체를 잠금 해제할 수 있습니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“MemoryLayout과 정렬”에서 뭘 배우나요?

형식의 크기, 간격, 정렬을 검사합니다. 브라우저에서 직접 실행하는 실습 코드로 Swift Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Swift Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Swift Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“MemoryLayout과 정렬” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Swift Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Swift Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. MemoryLayout과 정렬
  2. UnsafePointer와 UnsafeMutablePointer
  3. 안전하지 않은 버퍼 포인터
  4. withUnsafeBytes와 C 상호 운용
← Swift Academy(으)로 돌아가기