Coming from a .Net background, I wanted to understand how iOS or OS X does memory management. Here’s brief post on what I’ve read and understood so far.
Until a few years ago, Apple developers had to manually manage memory while writing Objective-C code. It was called the Manual Retain-Release model, and is exactly what developers have been doing all this while for C/C++.
But managing memory manually has always been painful and error prone, and takes up valuable time of application developers, which could instead be used for building useful features.
Enter ARC, acronym for Automatic Reference Counting.
Apple introduced ARC in 2011 along with Max OS X Lion and iOS 5.
With ARC, Apple has tried to make the compiler mimic what disciplined C/C++ developers would do. They would manually track the memory they are allocating for their code, and then ensure they release that memory whenever the objects go out of scope, and their memory is no longer required. So instead of the developers, now the compiler is doing all the hard work.
Its not like ARC was entirely Apple’s creation, Reference Counting has been around for a long time, and is one technique of implementing Garbage Collection.
How is ARC different from a Garbage Collector?
— Is part of the runtime infrastructure – i.e. part of CLR, JVM, and the runtime is responsible for running and monitoring the Garbage Collector (GC)
— Is indeterministic, so objects stick around until the GC runs, and therefore are not released as soon as they go out of scope
— Affects application performance when it runs, as other threads are paused, while it is runnning
— Is able to clear entire Object graphs, as it is able to figure out the application root object references while the application is running
— Is less prone to memory leaks
— It is not part of the runtime
— Instead the compiler injects reference tracking and clean-up code, similar to what a developer would do
— Deterministic reclamation of memory, at the time when the object goes out of scope
— Since there is no background or runtime processing, it requires less CPU and RAM, making it efficient on mobile devices
— Cannot cope with retain cycles/object graphs – gets stuck with an object graph, whereas a GC would look for an external reference to an object graph, and if not found would clear up the entire object graph
— Is more prone to memory leaks based on the quality of code written
A Retain Cycle is created when two or more objects are referencing each other in a circular fashion. For e.g. when we have a Parent – Child relationship between two objects, both instances would be referencing each other until they both go out of scope. This creates a circular reference and ARC is not able to figure out when to release these objects as it does not do a stack walk which a GC would do to find external references to these objects, instead ARC just tracks the count of the references to a particular object.
To solve this issue, Apple came out with Strong and Weak references. The Parent object creates a Strong reference to the Child object, which means that until the Parent object is deallocated, the Child object needs to remain alive. And the Child object creates a Weak reference to the Parent object, which breaks the circular reference cycle, and now the Parent object can be cleared whenever it goes out of scope, which in turn will also clear the Child object.
However, for the scenario above, developers need to handle missing or nil Parent objects in the Child object implementation, for when the Parent object gets deallocated and before the Child object is cleared, Child object code might be executed.
There is a concept of unowned references as well to prevent retain cycles, which I left out for now.
LLVM and Clang
Apple has used the LLVM compiler toolset to implement ARC.
“The LLVM Project is a collection of modular and reusable compiler and toolchain technologies”
The aim of LLVM is to provide a common backend compiler infrastructure to different compiler front-ends for different languages.
At a high level LLVM accepts code in an Intermediate Form and then is able to emit machine code based on the target architecture.
Ultimately we should be able to write code in different programming languages, run it through LLVM to generate native code for different platforms.
Apple developed the Clang frontend for C, C++, Objective-C and now Swift to use with LLVM. Clang is where the ARC magic happens.
Earlier Apple was using the GCC compiler for Objective-C and XCode, however as GCC is old and has a massive codebase to allow easy addition of new features and advancement, Apple decided to switch to the LLVM toolset. GCC also uses the GPL license, which would have forced Apple to GPL XCode’s source whereas LLVM uses the more lenient BSD license to protect proprietary software.
This was a short introduction to how iOS uses ARC to manage its memory, and about the tools that are used for ARC, do send in your feedback via comments. In future, I am planning to write a post on the tools which are available with XCode, which help diagnose memory related issues.
And other Stackoverflow threads and articles.