Sobes.tech
Junior

What is a memory leak and how does it occur?

sobes.tech AI

Answer from AI

Memory leak — is a situation where allocated memory is no longer used by the program but remains inaccessible to the garbage collector (or memory management system) because objects still reference it. In iOS, this occurs due to cyclic references between objects that use Automatic Reference Counting (ARC).

How it occurs:

ARC in iOS automatically manages memory by freeing objects when there are no active references to them. A leak occurs when two or more objects reference each other strongly (by default), creating a closed cycle. In this case, the reference count of each object never reaches zero, even if there are no external references to this group of objects. ARC cannot free these objects.

Example:

class Parent {
    var child: Child?
    // ...
    deinit {
        print("Parent deinitialized")
    }
}

class Child {
    var parent: Parent?
    // ...
    deinit {
        print("Child deinitialized")
    }
}

func createLeak() {
    let parent = Parent()
    let child = Child()

    parent.child = child
    child.parent = parent // Strong cyclic reference
}

createLeak()
// parent and child will exist after the function exits,
// even though there are no external references to them
// deinit messages will not be printed

In this example, parent strongly references child, and child strongly references parent. This creates a cycle. When createLeak finishes, the local variables parent and child go out of scope, but the strong references between the Parent and Child instances remain, preventing their deallocation by ARC.

To prevent memory leaks in iOS, weak and unowned references are used, which do not increase the reference count of the object.

  • weak: Used when the lifetime of objects can vary. A weak reference can become nil if the object it references is deallocated.
  • unowned: Used when the lifetime of the referencing object does not exceed the lifetime of the object it points to. An unowned reference always has a value and cannot be nil. Accessing a deallocated object via an unowned reference will cause a runtime error.
class Parent {
    var child: Child?
    // ...
    deinit {
        print("Parent deinitialized")
    }
}

class Child {
    weak var parent: Parent? // Using a weak reference
    // ...
    deinit {
        print("Child deinitialized")
    }
}

func fixLeak() {
    let parent = Parent()
    let child = Child()

    parent.child = child
    child.parent = parent // Now the parent-child link does not contain a cyclic strong reference
}

fixLeak()
// parent and child will be deallocated after the function exits,
// because the cyclic strong reference is eliminated
// deinit messages will be printed
What is a memory leak and how does it occur? — iOS - sobes.tech