What is a side table, and when does the runtime create one?

3.4.4 · L5 · Learning

Predict first

Which of these makes the Swift runtime allocate a side table?

// A: taking a strong reference
// B: taking a weak reference
// C: taking an unowned reference
  • A
  • B
  • C

Mental model. A normal object keeps its attendance sheet on its own door. The moment someone asks to be told when it leaves, the sheet moves into a separate office, and every visit now goes via the office.

A native object’s second header word packs its strong count, unowned count and some flags (such as “is deinitialising”) into one 64-bit value, so retain and release are a single atomic operation on the object itself. That is the fast path.

Some objects outgrow it. The first time you create a weak reference to an object (or when a count overflows its bits) the runtime allocates a separate side table on the heap, holding the counts and a pointer back to the object, and the object’s header word is changed to point to it. From then on every retain and release on that object goes through the side table, a slower path. The side table also outlives the object while weak references remain, so a weak read can safely ask “is it still alive?”, and it is freed when the last weak reference is gone.

Weak references need a record that survives the object’s death, so creating the first one allocates a side table. Strong and unowned counts fit in the inline header.

Common traps

  • “Weak references are free.” They cost a side table, a slower retain path for that object, and an atomic check on each read.
  • Creating weak references to hot objects “just in case”. You put them on the slow path for their whole life.

They might follow up with

  • Why does an unowned reference not need one? The unowned count fits in the inline header, so only weak needs the external record.
  • Is the object’s memory freed with the object? Not necessarily. The side table and (with unowned references) the husk can outlive deinit.

Related questions

  • 3.4.5 How does a weak reference get zeroed when the object dies?
  • 3.2.5 What happens to an object’s memory while unowned references to it still exist?
  • 3.2.1 What is the difference between strong, weak, unowned and unowned(unsafe)?

← What actually allocates on the heap in Swift, and how do you see it?   How does a weak reference get zeroed when the object dies? →