What actually allocates on the heap in Swift, and how do you see it?

3.4.3 · L3 · Interview

Predict first

What does this print, in bytes?

print(MemoryLayout<() -> Void>.size, MemoryLayout<String>.size)
  • 8 8
  • 16 16
  • 8 24

Mental model. A value is a note kept in your pocket. A heap object is a locker you rent: costly to open, and everyone with the key has to be tracked.

Structs, enums and tuples are stored inline where they live (in a stack frame, in another object, in an array’s buffer) and need no allocation of their own. The heap is used for: class instances; the buffers of arrays, dictionaries, sets and long strings; closure contexts and boxes for variables captured by an escaping closure; existential boxes for values bigger than three words; indirect enum payloads; and the frames of async work. A small non-escaping closure and a small string (up to 15 UTF-8 bytes, stored inside the 16-byte String) need none.

The optimiser can promote some allocations to the stack when it can prove they do not escape, so reading source is not enough. Measure: the Allocations instrument shows each allocation and its call stack, and a breakpoint on swift_allocObject catches class allocations. Reduce allocations in hot paths by using value types, reserving capacity, avoiding existentials in tight loops, and not creating closures per iteration.

A closure value is a function pointer plus a context pointer; a String is 16 bytes and stores short text inline without allocating.

Common traps

  • “Structs never touch the heap.” A struct that holds an array or class reference points into the heap; the struct itself may be boxed when captured or existential.
  • Guessing instead of measuring. Stack promotion and inlining change the answer between Debug and Release.

They might follow up with

  • Where do the three-word existential and the stack/heap story appear? In the Types section: stack-or-heap and existential container questions.
  • What does a closure value cost? Two words: a function pointer and a context pointer. The context is heap-allocated only if it captures something.

Related questions

  • 1.1.3 Where do value types live — stack or heap?
  • 1.4.6 What is an existential container? What is a witness table?
  • 3.4.1 What does a class instance look like in memory?

← What do MemoryLayout’s size, stride and alignment mean, and why does…   What is a side table, and when does the runtime create one? →