What is the difference between stack and heap memory in Swift?
TL;DR
The stack is fast memory for local data. It is freed automatically when a function returns. The heap is memory for data that must live longer or has a size known only at run time. It needs allocation and ARC. "Structs go on the stack, classes go on the heap" is a good start, but not the full truth. Interviewers like it when you know the exceptions.
The stack
Each thread has its own stack. Calling a function pushes a frame with its local values. Returning pops it.
func area(width: Double, height: Double) -> Double {
let result = width * height // stored in this function's frame
return result
} // frame popped, memory free- Allocation is just moving a pointer. Very fast.
- No locking. Each thread has its own stack.
- Size is limited. Main thread: about 1 MB on iOS by default; secondary threads: 512 KB. Deep recursion can overflow it.
The heap
Shared by all threads. Used for data that must outlive the function or that is too big or dynamic.
final class User {
var name: String
init(name: String) { self.name = name }
}
func makeUser() -> User {
User(name: "Ana") // allocated on the heap, returned by reference
}- Allocation must find a free block. It is thread-safe, so it has a cost.
- ARC counts references, and frees the memory at zero.
- Data can live as long as needed.
Comparison
| Stack | Heap | |
|---|---|---|
| Speed | Very fast (move a pointer) | Slower (find a block, thread safety) |
| Lifetime | Until the function returns | Until the last strong reference goes away |
| Managed by | Compiler automatically | ARC (for class instances) |
| Shared between threads | No | Yes |
| Size | Small, fixed per thread | Large |
What actually goes where
| Thing | Usually |
|---|---|
Local Int, Double, small struct | Stack (or CPU registers) |
| Class or actor instance | Heap |
Array, Dictionary, Set elements | Heap (the struct itself is small) |
String | Inline if small (up to 15 UTF-8 bytes), heap if larger |
| Value captured by an escaping closure | Heap (in a box) |
Large value in any Protocol | Heap (more than 3 words does not fit the inline buffer) |
indirect enum case | Heap |
Exceptions you should mention
A struct can live on the heap
struct Point { var x = 0.0, y = 0.0 }
let points = [Point(), Point()] // the Points are in the array's heap buffer
final class Shape { var origin = Point() } // stored inside a heap objectCaptured variables move to the heap
func makeCounter() -> () -> Int {
var count = 0 // captured, so Swift boxes it on the heap
return {
count += 1
return count
}
}count must outlive makeCounter, so it cannot stay on the stack.
A class can live on the stack
If the optimizer proves an object never escapes the function, it can allocate it on the stack. This is called stack promotion.
func compute() -> Int {
let helper = Helper() // may be stack-promoted if it never escapes
return helper.run()
}Why it matters for performance
Heap allocation and reference counting are among the most common costs in Swift code. To reduce them:
- Prefer structs with simple stored properties for small models.
- Avoid
any Protocolin hot loops. Use generics orsome. - Reserve capacity:
array.reserveCapacity(1_000)avoids repeated reallocations. - Mark classes
final. It helps the optimizer. - Profile with Instruments (Allocations) before you optimize.
A struct with many class references (or Strings and arrays) is not free to copy. Every copy retains each reference.
Common follow-up questions
- What is a stack overflow? The stack runs out of space, usually from infinite or very deep recursion. The app crashes.
- Are value types always faster? No. A large struct with many references can cost more to copy than passing one class reference.
- What is the inline buffer of an existential?
any Preserves three words for the value. Bigger values are boxed on the heap. - Can you choose stack or heap yourself? Not directly. You choose value vs reference types and the compiler decides.
withUnsafeTemporaryAllocationgives stack memory when possible. - Does Swift 6 add anything here? Yes.
InlineArray(Swift 6.2) is a fixed-size array stored inline, with no heap buffer.Spangives safe access to memory without copying.