# Automatic Reference Counting

## Overview

If you have read the section on [C++ Smart Pointers](https://ir0nstone.gitbook.io/notes/binexp/memory-safety/c++-smart-pointers), you actually pretty much understand ARC. In languages such as Swift, where ARC is used as the only memory management tool, effectively every class instance is used as a `shared_ptr`. The official documentation is [here](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/).

Officially, every time a class instance is assigned to a property, constant or variable it creates a **strong reference** to the instance. The reference is called "strong" because the instance cannot be deallocated as long as one such reference exists. Every time one of these properties, constants or variables have their references removed, through something like reaching the end of their lifetime or through reassignment, the reference counter of the class instance drops. Once it reaches zero, the instance is deallocated.

## Drawback: Reference Cycles

One of the downsides of ARC is the idea of **reference cycles** (also called **retain cycles**), where two class instances have strong references to one another. A minimal example is as follows:

```swift
class A {
    var b: B?
}

class B {
    var a: A?
}

let a = A()
let b = B()
a.b = b
b.a = a
```

Note that here the instance of `A` has two strong references (`a` and `b.a`) while the instance of `B` also has two strong references (`b` and `a.b`).

If `a` and `b` go out of scope, the strong references to the instances of `A` and `B` will disappear, and the reference count will decrement to `1` for both instances. But `a.b` and `b.a` will still point at the instances of `A` and `B` respectively, so the instances will not be automatically deallocated. Similarly, they will **never** be deallocated, as `a.b` and `b.a` are no longer accessible, even though they still have strong references! This leads to memory leaks, and is one of the main drawbacks of ARC.

## Drawback: Multi-threading

Reference counting can lead to memory-unsafe execution if a program is multi-threaded, as one thread may delete the object as it is being used by another. This issue does not occur in garbage-collected programming languages.

## Uses of ARC

Having a programming language that uses purely ARC is very rare - only Apple's languages, Objective-C and Swift, do this.

Python [does count references](https://docs.python.org/3/glossary.html#term-reference-count), but it [also has a garbage collector](https://docs.python.org/3/glossary.html#term-garbage-collection) to detect and break reference cycles. Up until Python 3.13, the [Global Interpreter Lock](https://blog.jetbrains.com/pycharm/2025/07/faster-python-unlocking-the-python-global-interpreter-lock/) (GIL) meant that multi-threading in Python was actually all on one thread, which counteracted the multi-threading race condition. With the removal of the GIL, [some extra work](https://peps.python.org/pep-0703/) was needed to fix this problem.
