A blog notes series on how memory works under the hood in iOS
The Stack and the Heap
Memory during a program run on an iOS device is generally divided into the stack and the heap. There is other stuff but the stack and the heap are the main areas.
Each thread has its own stack of frames, which represent function calls. Its variables are more local and shorter-lived than those in the heap. The stack is much more local than the heap and its space is strictly limited.
The heap is an unbounded area of memory where objects generally are stored. It can be accessed by any of the threads and their stacks. Because of this, variables in the heap are more global in nature.
During the course of a thread’s run loop each stack’s frames grow and shrink depending on the function calls. As each function calls another function then exits, the frame (representing a function) is popped off.
Once a frame is pushed off as a function exits, its variables are lost forever… unless they are pointers to the heap.
You can actually see the frames of the main thread’s stack in your xcode debugger from this Big Nerd Ranch code sample. (The series especially the Objective-C book are really some of my favorite book learning, highly recommended!)
Pointers from the Stack to the Heap
When you’re inside a frame you can point to an object on the stack:
- (void)createString {
// this is in a frame on the stack
int stackNumber = 42;
printf("%d is in a frame on the stack and will vanish as this function exits", stackNumber);
// this lives on the heap
NSAttributedString *heapString = [[NSAttributedString alloc] initWithString:@"Nice String"];
NSLog(@"%@", heapString);
}
As the programmer writes her code, it’s her responsibility to keep as few objects and variables in memory as possible. The less objects to keep track of the better for both mental clarity as well as performance in the code.
Luckily there’s a lot of help from Automatic Reference Counting (ARC). While not true garbage collection, ARC is an invaluable assistant in Apple’s Memory Management, adding just the right code at the right time to dispose of objects in the heap.
The programmer is still responsible for keeping down the excessive number of objects and variables in memory which can still happen despite ARC, especially if a lot of memory is allocated very quickly at once.
Reference Counting
The phone-computer knows to keep objects alive as long as they need to be in the heap through reference counting. An object can keep another object alive by holding a strong reference to it…
You can run into problems if you unwittingly allow objects to hold strong references to each other. This creates a retain cycle. Both objects will keep each other alive and cause memory leaks. Get too many of these and they quickly balloon out of control!
From Apple:
// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html#//apple_ref/doc/uid/TP40011210-CH8-SW16
@interface XYZBlockKeeper : NSObject
@property (copy) void (^block)(void);
@end
@implementation XYZBlockKeeper
- (void)configureBlock {
self.block = ^{
[self doSomething]; // capturing a strong reference to self
// creates a strong reference cycle
};
}
...
@end
There can also be some pretty nasty crashes (stackOverflow example)
// https://stackoverflow.com/questions/23806751/strong-reference-to-a-weak-references-inside-blocks
__weak typeof(self) weakSelf = self;
void (^someBlock)(id) = ^(id data){
if (weakSelf != nil) {
// last remaining strong reference released by another thread.
// weakSelf is now set to nil.
[myArray addObject:weakSelf];
}
});
The solution for potential retain cycles is for an object to hold another object as a weak reference. That way an object can keep in contact with another object without keeping it alive.
In Swift the safeguarding looks like this:
class ComicBook: Book {
weak var comicDelegate: ComicDelegate?
}
It’s pretty fascinating stuff, part of my regrets not starting out with C to begin with as I should have in college, when I cancelled an intro to C course. I’m learning that there are languages like C++ where objects live in the stack, and as I learn more I’m seeing at all the incredible feats (and disasters) that can happen was engineers work to optimize and juggle bits to create better, more reliable and beautiful experiences.
In short, I’m beginning to learn more and in doing so learning what i don’t know! But this blog series will be a fun ride, I think.
Readings
mike ash: Friday q&a 2010 — stack and heap objects in objective-C
paul gribble: stack and heap notes for C
Big Nerd Ranch: Objective-C Book
Big Nerd Ranch: iOS Developers Need to Know Objective-C
RayWenderlich: Beginning ARC in iOS 5 Tutorial Part 1