Swift의 Memory Layout 이해하기

2026. 9. 15. 15:30·Programing Langauge/swift
반응형

👋 들어가기 전

Swift에서 데이터를 Bytes로 변환하거나 반대로 Bytes에서 특정 타입으로 변환하는 코드를 보다 보면 MemoryLayout, alignment, padding, stride와 같은 개념을 마주치게 된다.

 

처음에는 단순히

객체 → Bytes
Bytes → 객체

 

정도로 생각할 수 있지만, 메모리에 실제 데이터가 어떻게 배치되어 있는지를 이해하지 못하면 이런 코드의 동작을 정확하게 이해하기 어렵다.

 

특히 UnsafeRawPointer, withUnsafeBytes 등을 사용하는 코드에서는 Swift의 추상화된 값이 실제 메모리에서 어떻게 표현되는지를 알아야 한다.

 

이번 글에서는 먼저 Swift의 메모리 레이아웃을 간단하게 살펴보자.


🏁 학습할 내용

  • Swift 메모리 레이아웃의 4대 요소
  • MemoryLayout<T>을 통해 실제 분석해보기

✊ Swift 메모리 레이아웃 4대 요소

 

Swift는 데이터 접근 성능을 최적화하기 위해 메모리 정렬(Alignment)과 패딩(Padding)을 사용한다.

  • Size (크기)
    • 타입의 순수한 데이터가 실제로 차지하는 바이트 수
    • 타입의 인스턴스를 저장하는 데 필요한 최소한의 공간
  • Stride (보폭 / 간격)
    • 동일한 타입의 인스턴스들을 배열 형태로 연속 배치할 때 인스턴스 간의 바이트 간격
    • Stride = Size + Padding 공식이 성립하며, 다음 인스턴스가 올바른 Alignment 위치에 시작할 수 있도록 패딩 바이트가 포함됨
  • Alignment (정렬)
    • 해당 타입의 인스턴스가 메모리에 할당될 때 시작 주소가 나누어 떨어져야 하는 바이트 단위
    • 예를 들어, Alignment가 8이면 메모리 주소는 반드시 8의 배수(0x...0, 0x...8 등)여야 한다.
      CPU가 효율적으로 데이터를 읽고 쓰기 위한 필수 조건이다.
  • Padding (빈공간)
    • CPU가 메모리에 빠르게 접근할 수 있도록, 데이터와 데이터 사이에 넣어두는 "의미 없는 빈 바이트(Dummy Bytes)
    • 내부 패딩 (Internal Padding / Alignment Padding)
      • 원인: 다음 필드의 Alignment 기준을 맞추기 위해 필드 사이에 들어감
      • 영향: Size에 포함됩니다.
    • 후미 패딩 (Tail Padding)
      • 원인: 배열에서 다음 인스턴스가 올바른 Alignment 주소에서 시작되도록 구조체 맨 끝에 붙음
      • 영향: Size에는 안 들어가고, Stride에만 포함됩니다.

 

패딩을 포함하면 4가지 수식 관계가 깔끔하게 정리됩니다.

  • Size =모든 필드의 순수 크기 + 내부 패딩
  • Stride = Size + 후미 패딩
  • Stride는 반드시 Alignment의 배수

☝️MemoryLayout<T>을 통해 실제 분석해보기

 

기본

// 1. 기본 Int (64비트 시스템 기준)
print(MemoryLayout<Int>.size)      // 8
print(MemoryLayout<Int>.stride)    // 8
print(MemoryLayout<Int>.alignment) // 8

// 2. 패딩이 발생하는 구조체
struct Example {
    let a: Int8   // 1 byte
    let b: Int64  // 8 bytes
    let c: Int32  // 4 bytes
}

print(MemoryLayout<Example>.size)      // 20 (1 +7패딩 + 8 + 4)
print(MemoryLayout<Example>.stride)    // 24 (20 + 4패딩 -> 8의 배수로 정렬)
print(MemoryLayout<Example>.alignment) // 8 (가장 큰 필드인 Int64의 alignment)

 

  • Example 구조체 내부의 가장 큰 멤버는 Int64(Alignment = 8), 따라서 구조체 전체의 Alignment는 8이 됩니다.
  • a (1 byte) 뒤에 b가 오려면 8의 배수 주소에 맞춰야 하므로 7바이트의 패딩이 들어감.
  • c (4 bytes)까지 더해진 순수 크기(size)는 1 + 7 + 8 + 4 = 20바이트입니다.
  • 배열 등에서 연속 배치(stride)될 때 다음 요소도 8의 배수 주소에서 시작해야 하므로, 끝에 4바이트의 패딩이 추가되어 stride는 24가 됩니다.

 

필드 순서에 따른 최적화

// 메모리 낭비가 발생하는 구조체
struct Unoptimized {
    let a: Int8   // 1 byte
    let b: Int64  // 8 bytes
    let c: Int8   // 1 byte
}

// 필드 순서를 재배치하여 최적화한 구조체
struct Optimized {
    let b: Int64  // 8 bytes
    let a: Int8   // 1 byte
    let c: Int8   // 1 byte
}

print(MemoryLayout<Unoptimized>.size)   // 17
print(MemoryLayout<Unoptimized>.stride) // 24

print(MemoryLayout<Optimized>.size)     // 10 (8 + 1 + 1)
print(MemoryLayout<Optimized>.stride)   // 16 (10 + 6패딩 -> 8의 배수)

 

 

필드 재배치 최적화의 핵심 규칙은 "Alignment(정렬 기준)가 큰 타입부터 작은 타입 순서대로(내림차순)" 배치하는 것

 

패딩 계산

 

struct Sample {
    let a: Int8   // 1 byte
    let b: Int64  // 8 bytes
    let c: Int32  // 4 bytes
}

// 1. 순수 데이터 바이트의 합
let pureDataSize = MemoryLayout<Int8>.size + MemoryLayout<Int64>.size + MemoryLayout<Int32>.size // 13 bytes

// 2. 내부 패딩 = Size - 순수 데이터 크기
let internalPadding = MemoryLayout<Sample>.size - pureDataSize
// 20 - 13 = 7 bytes (a 뒤에 들어가는 7바이트 패딩)

// 3. 후미 패딩 = Stride - Size
let tailPadding = MemoryLayout<Sample>.stride - MemoryLayout<Sample>.size
// 24 - 20 = 4 bytes

// 4. 총 패딩 수
let totalPadding = internalPadding + tailPadding
// 7 + 4 = 11 bytes

print(pureDataSize,internalPadding,tailPadding, totalPadding) // 13 7 4 11

출처

반응형

'Programing Langauge > swift' 카테고리의 다른 글

InlineArray와 Span  (0) 2026.09.09
SIL로 Swift 클로저 뜯어보기  (0) 2026.07.27
소유권이란?  (1) 2026.07.14
defer  (0) 2026.01.31
퀵 헬프 주석  (0) 2026.01.14
'Programing Langauge/swift' 카테고리의 다른 글
  • InlineArray와 Span
  • SIL로 Swift 클로저 뜯어보기
  • 소유권이란?
  • defer
Hamp
Hamp
남들에게 보여주기 부끄러운 잡다한 글을 적어 나가는 자칭 기술 블로그입니다.
  • Hamp
    Hamp의 분리수거함
    Hamp
  • 전체
    오늘
    어제
    • 분류 전체보기 (345)
      • CS (30)
        • 객체지향 (2)
        • Network (7)
        • OS (6)
        • 자료구조 (1)
        • LiveStreaming (3)
        • 이미지 (1)
        • 잡다한 질문 정리 (0)
        • Hardware (2)
        • 이론 (6)
        • 컴퓨터 그래픽스 (0)
      • Firebase (3)
      • Programing Langauge (45)
        • swift (38)
        • python (6)
        • Kotlin (1)
      • iOS (136)
        • UIKit (37)
        • Combine (1)
        • SwiftUI (35)
        • Framework (7)
        • Swift Concurrency (22)
        • Tuist (6)
        • Setting (11)
        • Modularization (2)
        • Instruments (6)
      • PS (59)
        • 프로그래머스 (24)
        • 백준 (13)
        • LeetCode (19)
        • 알고리즘 (3)
      • Git (18)
        • 명령어 (4)
        • 이론 (2)
        • hooks (1)
        • config (2)
        • action (7)
      • Shell Script (2)
      • Linux (6)
        • 명령어 (5)
      • Spring (21)
        • 어노테이션 (6)
        • 튜토리얼 (14)
      • CI-CD (4)
      • Android (0)
        • Jetpack Compose (0)
      • AI (21)
        • 이론 (10)
        • MCP (1)
        • LangGraph (10)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    boostcamp
    dfs
    Swift
    dp
    투포인터
    프로그래머스
    IOS
    Spring
    protocol
    lifecycle
    CS
    concurrency
    property
    SwiftUI
    UIKit
    Tuist
    백준
    dispatch
    AVFoundation
    GIT
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.0
Hamp
Swift의 Memory Layout 이해하기
상단으로

티스토리툴바