What does a class instance look like in memory?
Predict first
What sizes does the runtime report, in bytes?
import ObjectiveC
final class Empty {}
final class One { var a = 0 }
final class Two { var a = 0; var b = true }
print(class_getInstanceSize(Empty.self), class_getInstanceSize(One.self), class_getInstanceSize(Two.self))
- 0 8 9
- 16 24 25
- 16 24 32
Mental model. Every object arrives in a box with a 16-byte shipping label on the front. The label says what it is and how many people hold it.
A Swift class instance is a heap block that starts with a 16-byte header: a pointer to the type’s metadata (which gives the runtime its class, vtable and layout), and a word holding the inline reference counts. Your stored properties follow, laid out in declaration order with the usual alignment padding. An empty class is 16 bytes; add an Int and it is 24; add a Bool as well and it rounds up to 32, not 25.
That header is why a class costs more than a struct holding the same fields: 16 extra bytes, an allocation (malloc), reference-count traffic on every copy, and an indirection to reach the data. MemoryLayout measures structs; for a class, class_getInstanceSize (from ObjectiveC) reports the instance size, and MemoryLayout<SomeClass>.size is only the 8-byte reference.
The 16-byte header, plus 8 for the Int, plus 1 for the Bool, rounded up to the next 8: 32.
Common traps
- Using
MemoryLayout<MyClass>.sizeto size an object. That is the pointer, always 8 bytes. Useclass_getInstanceSize. - Adding up field sizes. Alignment rounds the total: 8 + 1 on top of the header becomes 32, not 25.
They might follow up with
- What is in the second header word? The strong and unowned counts plus flags. See the side-table question.
- Does a subclass add another header? No. It appends its own fields after the superclass’s.
Related questions
- 3.4.2 What do MemoryLayout’s size, stride and alignment mean, and why does field order matter?
- 3.4.4 What is a side table, and when does the runtime create one?
- 3.4.3 What actually allocates on the heap in Swift, and how do you see it?
What do MemoryLayout’s size, stride and alignment mean, and why does… →