---
title: "Dive into Swift's Memory Management"
slug: "dive-into-swifts-memory-management"
date: "2023-01-08T19:33:03.000Z"
description: "Swift uses ARC to track and deallocate unused objects. Learn about the three types of reference counts and how ARC works — in this detailed post."
---

# Dive into Swift's Memory Management

In this post, I'll explore how Swift's memory management works under the hood, and how the memory modifiers: `unowned` and `weak`, affect an object's lifetime. You'll get a deeper understanding of how Swift manages objects' lifetime internally.

💥

Swift memory management is one of the basic interview questions. It was asked ****in every**** iOS developer interview I've ever been to

## Memory Management

For example, in C, only the developer is in charge of deallocating unused objects. This can lead to memory leaks, double deallocations, or the use of invalid memory areas.

We don't want this.

Swift uses automatic reference counting (ARC) under the hood to deduce objects' lifetime and automatically deallocate unused objects. Swift has **three different types of the reference count.** They count how many other instances use an object. And when it is not needed, it is deallocated.

💡

This guide will progress from a general overview to the internals of ARC. Even if you're familiar with Swift's memory management, there's a high chance that you will learn something new

## Strong Reference

The counter that is responsible for deallocation is a **strong reference counter (RC).** The strong RC counts strong references to the object. When the strong RC reaches zero the object is deinited.

A strong reference is just a regular object usage. Creating a variable, or a constant, or saving a reference to an object in another object's property — they all create a strong reference.

Why a developer should even care about reference counting? Seems like a low-level implementation detail that is not important. **But actually, it's crucial.**

Take a look at this example

```swift
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")

john!.apartment = unit4A // Person -> Apartment: strong reference
unit4A!.tenant = john // Apartment -> Person: strong reference

john = nil // Person is no longer needed
unit4A = nil // Apartment is no longer needed
```

In the above example, the `Person` and `Apartment` objects have a strong reference to each other, creating a **retain cycle**. As a result, when you set both `john` and `unit4A` to `nil`, the **deinitializers are not called and the objects are not deallocated.**

![Retain cycle image](https://alexdremov.me/content/images/2023/01/strongRef.png)

💥

This situation is called a ****memory leak****. In Swift, it occurs only in the case of a ****retain cycle.**** Two objects depend on each other and they will never be deallocated.

That's where memory management modifiers come in handy.

## Weak Reference

One of the solutions to the problem of a retain cycle is a **weak reference.** It is created using the `weak` modifier like that:

```swift
let person = Person(name: "John Appleseed") // person is a strong reference
weak var weakPerson = person // weak reference to the same object
```

Weak var **always has an optional type** and cannot be constant (`let`). That's because the object can be deallocated while it is still referenced by a weak variable. In this case, the variable is automatically set to `nil`.

💡

Consider `weak` reference like the one that needs an object but can go on correctly without it (using `nil`), allowing it to deallocate when nobody else needs it

Let's take a look at the solution to the problem above using the `weak` modifier:

```swift
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    
    weak var tenant: Person?
    
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")

john!.apartment = unit4A // Person -> Apartment: strong reference
unit4A!.tenant = john // Apartment -> Person: weak reference

john = nil
unit4A = nil
```

![Strong and weak reference image](https://alexdremov.me/content/images/2023/01/weakRef.png)

Now, retain cycle is no longer here. At first, the `Person` object is deallocated because it has no strong references to it. Then, the `Apartment` object is deallocated.

No memory leak!

That's it. That is how you break retention cycles in Swift. There is one more modifier that can help you with that.

## Unowned Reference

An `unowned` reference is very similar to a `weak` reference cause it also does not increase a strong reference count. The difference is that it's up to the developer to not use an invalid object.

Unowned variables **can be constant or non-optional.** When an object is deallocated, **ARC does not set the unowned reference’s value to `nil`**. However, if you try to access a deallocated object, you will catch a runtime error.

😡

Use an unowned reference only when you are sure that the reference always refers to an instance that has not been deallocated

Here's a similar example:

```swift
class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) {
        self.name = name
    }
    deinit { print("\(name) is being deinitialized") }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("Card #\(number) is being deinitialized") }
}

var john: Customer? = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

john = nil // No retain cycle, both objects are deallocated
```

Subscribe and don't miss posts!

## Three Reference Counters

So, how does all this magic works inside? [Swift sources](https://github.com/apple/swift/blob/main/stdlib/public/SwiftShims/swift/shims/RefCount.h) have an amazing detailed description of all processes under the hood.

The **strong RC** counts strong references to the object. When the strong RC reaches zero the object is deinited, unowned reference reads become errors, and weak reference reads become nil. The strong RC is stored as an extra count: when the physical field is 0 the logical value is 1.

The **unowned RC** counts unowned references to the object. The unowned RC also has an extra `+1` on behalf of the strong references; this `+1` is decremented after deinit completes. When the unowned RC reaches zero the object's allocation is freed.

The **weak RC** counts weak references to the object. The weak RC also has an extra `+1` on behalf of the unowned references; this `+1` is decremented after the object's allocation is freed. When the weak RC reaches zero the object's side table entry is freed.

But what is a side table and why is it needed?

💥

What's side table is another popular interview question, usually more advanced

## Side Table

An object conceptually has three refcounts. These refcounts are stored either "inline" or in a "side table entry" pointed to by the internal field. You cannot access these fields from Swift directly

```swift
class User {
	var id: Int
    var name: String
    
    init(id: Int, name: String) {
    	self.id = id
        self.name = name
    }
}

let user = User(id: 0, name: "John")
```

![](https://alexdremov.me/content/images/2023/01/Screenshot-2023-01-08-at-15.12.40.png)

💡

Remember that unowned has `+1` on behalf of strong reference and weak has `+1` on behalf of unowned references

Objects initially start with no side table. They can gain a side table when a weak reference is formed.

Gaining a side table entry is a one-way operation; an object with a side table entry never loses it. This prevents some thread races.

```swift
weak var weakUser = user // Side table implicitly created
```

![A side table is created](https://alexdremov.me/content/images/2023/01/Screenshot-2023-01-08-at-15.20.34.png)

A side table is created

Strong and unowned variables point at the object. Weak variables point at the object's side table.

This idea is fundamental to understanding how `weak` references work. By pointing not to the object but to the side table, the object itself can be deinitialized and fully deallocated.

## Weak and Unowned. Deep Differences

Now, by looking at the implementation we can notice important differences between `weak` and `unowned`.

### Performance

Using `unowned` introduces less overhead than using `weak`. That's because `weak` variables reference the object through a side table. This means that there's one more pointer hop to reach the object.

Unowned references point directly to the object, so they do not have such overhead.

### Deallocation vs deinitialization

According to the sources, when the strong RC reaches zero the object is **deinited.** And when the unowned RC reaches zero the **object's allocation is freed**.

That means that object memory is not available for realocation until all unowned references disappear.

💥

If an object holds a large amount of memory, its memory will not be available until the last unowned reference disappear.If lack of memory is a problem, consider using `weak` reference because it allows objects to be fully deallocated even when there are alive `weak` references.

## Common Problems

The example of `Person` and `Apartment` retain cycle can be trivial. It's important to know about common cases when retain cycle appears.

### Closures, strong capture, and self

By default, a closure expression captures constants and variables from its surrounding scope with strong references to those values.

As we've already noted, uncontrollable strong references may create a retain cycle. An escaping closure that refers to `self` needs special consideration if `self` refers to an instance of a class. Capturing `self` in an escaping closure makes it easy to accidentally create a strong reference cycle.

For example:

```swift
class Person {
  var name: String
  var voice: Voice? = nil

  init(name: String) {
    self.name = name
    self.voice = Voice {
      print("I'm \(self.name)")
    }
  }
  func say() { voice?.say() }
  deinit {
    print("Person deallocated")
  }
}

class Voice {
  var say: () -> ()
  init(say: @escaping () -> ()) { self.say = say }
  deinit {
    print("Voice deallocated")
  }
}

var person: Person? = Person(name: "Alex")
person!.say()

person = nil
```

Which outputs only this line — without `deinit` prints

```
My name is Alex
```

What's going on here? Let's draw a strong references graph:

![Retain cycle with closure](https://alexdremov.me/content/images/2023/01/Screenshot-2023-01-08-at-16.22.35.png)

Retain cycle with closure

And, as expected, there is a pretty notable strong reference cycle. The problem is in the creation of the `Voice` instance:

```swift
self.voice = Voice {
	print("My name is \(self.name)")
}
```

Here, `self` is captured with a strong reference to the escaping closure. To solve that, we can capture `self` with the `weak` modifier:

```swift
self.voice = Voice {[weak self] in
	guard let self = self else { return; }
	print("My name is \(self.name)")
}
```

With such modification, we receive an expected output:

```
My name is Alex
Person deallocated
Voice deallocated
```

💥

Do not use `weak self` when it is not needed. Remember that strong reference is required so that object is not deallocated before it is needed.

## Final notes

If you want to achieve an even deeper understanding of ARC internals, definitely check the ARC source code. You can start with this amazing description of an object's lifetime state machine.

[

swift/RefCount.h at 3bac57d9ac20eb9a6e41fd3c32e8d6fb23e37a47 · apple/swift

The Swift Programming Language. Contribute to apple/swift development by creating an account on GitHub.

![](https://github.com/fluidicon.png)GitHubapple

![](https://opengraph.githubassets.com/1b258a6f968eb7c1af3235e6e4954c458d8edcd16fdb3a7e0e477002d51f4095/apple/swift)

](https://github.com/apple/swift/blob/3bac57d9ac20eb9a6e41fd3c32e8d6fb23e37a47/stdlib/public/SwiftShims/swift/shims/RefCount.h#L112)

Hope that this post was helpful to you. Feel free to leave a comment or to reach me through my social nets!

## References

[

swift/RefCount.h at main · apple/swift

The Swift Programming Language. Contribute to apple/swift development by creating an account on GitHub.

![](https://github.com/fluidicon.png)GitHubapple

![](https://opengraph.githubassets.com/1b258a6f968eb7c1af3235e6e4954c458d8edcd16fdb3a7e0e477002d51f4095/apple/swift)

](https://github.com/apple/swift/blob/main/stdlib/public/SwiftShims/swift/shims/RefCount.h)

[

Memory Management in Swift: Understanding Strong, Weak and Unowned References

Behind all the coding that we are doing, you probably have noticed some of your variables with the reference of strong, weak or unowned…

![](https://cdn-static-1.medium.com/_/fp/icons/Medium-Avatar-500x500.svg)AppCoda TutorialsAppCoda

![](https://miro.medium.com/max/1200/1*ky03wTVr4G93J_b1pi4VFQ.jpeg)

](https://medium.com/appcoda-tutorials/memory-management-in-swift-understanding-strong-weak-and-unowned-references-b80a06c82460)

[

Documentation

![](https://alexdremov.me/content/images/icon/favicon-080bba1d-a206-471b-a088-0204225c8ba7.ico)Swift.org



](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting)