Contents
Tips For Memory Management in Objective-C
Pham Van Hoang, hoangk55cd@gmail.com, is the author of this article and he contributes to RobustTechHouse Blog
Introduction
Managing memory is very important and necessary step for any programming language, especially for devices that run on a limited amount of memory such as mobile phones and smart watches. Since iOS5, Apple has introduced Automatic Reference Counting (ARC) that makes automatic memory management possible for Objective-C objects, simplifying a developer’s job from having to manage the memory manually. However, ARC is different from Garbage collection and does not impose runtime memory model as Garbage collection does. Therefore, even with ARC, memory issues can still happen and can crash your app when system is in a state of low-memory. In this article, we will introduce you some tips to manage more memory efficiently.
Memory Management Tips
Observe Low-Memory Warnings And Respond To It Immediately
When a system is in low-memory, it will dispatch a warning to your app. Low-memory warning is your opportunity to immediately free up any unnecessary memory hogging routines such as caches and images. If you fail to response to these warnings, your app will be likely to be terminated by the OS. The system that delivers memory warnings to your app uses the following APIs :
- TheapplicationDidReceiveMemoryWarning: method of Appdelegate.
- ThedidReceiveMemoryWarning method of the UIViewController
- TheUIApplicationDidReceiveMemoryWarningNotification notification.
If you need a way to trigger a memory warning so that you can write and test your memory cleanup code in your app, Xcode provides an option to simulate memory warning without having to write any code. You just need to click on Hardware > Simulate Memory Warning and Xcode will do the rest.
Avoid Strong Cycle (Strong Reference Cycles Between Class Instances)
This is quite a common mistake for developers and it can cause a memory leak (a piece of memory that has lost tracked and would never be deallocated by program). To understand more about the strong cycle, we will look at how ARC deallocates an object. In Apple document:
“ARC will not deallocate an instance as long as at least one active reference to that instance still exists. To make this possible, whenever you assign a class instance to a property, constant, or variable, that property, constant, or variable makes a strong reference to the instance. The reference is called a strong reference because it keeps a firm hold on that instance, and does not allow it to be deallocated for as long as that strong reference remains.“
This problem occurs when one object has a ‘strong’ pointer to another and the target object has a ‘strong’ pointer back to the original. When all other references to these objects are set to nil, they will still continue to be referenced to one another and will not be deallocated. This can also happen by a chain of objects that might have the last one in the chain referring back to an earlier object.
Here is an simple example:
In this example, we have a class Person and a class Apartment. A person has an apartment called unit4A. And in object Apartment we have a tenant link to john.
Now you will quickly see what called Strong cycle since Person instance has strong reference to Apartment instance, and Apartment instance has strong reference to Person instance.
When we attempt to deallocate these objects by set two instances john = nil and unit4A = nil, the reference counts do not drop to zero. Therefore, the instances are not deallocated and they will stay in the memory until either system or user terminates the application.
To fix the problem, you need to add weak property in the tenant reference since weak reference does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance.
You can see more information on how to use the weak reference here (do note that the example is written in swift language but it is very easy to understand).
Using Autorelease Pool Blocks
An autorelease pool block is marked using @autoreleasepool. You should consider using @autorealease in your program in the following cases (based on recommendations from Apple):
- If you create a second thread, you must create your own autorelease pool block as soon as the thread begins executing; otherwise, your application will leak objects.
- If you write a loop that creates many temporary objects.
You may use an autorelease pool block inside the loop to dispose of those objects before the next iteration. Using an autorelease pool block in the loop helps to reduce the maximum memory footprint of the application, especially for convenience methods.
Let’s try this example:
- (void)viewDidLoad { [super viewDidLoad]; for (int j = 0; j < 4; ++j) { @autoreleasepool { for (int i = 0; i < 10000; ++i) { UIImage *image = [UIImage imageNamed:@"test_image"]; NSLog(@"%@", image.description); } } } }
If you run the allocations instruments, you will see an allocations graph as following:
But if you remove the @autoreleasepool, you’ll see that peak memory usage is much higher:
See more about @autorealeasepool in apple document here
Reduce Your App Memory Footprint
Keeping your app in a low memory footprint gives you more room for expanding your app later and makes your app runs more smoothly. Here are some recommendations to reduce your app memory footprint:
- Load resouces lazily: You should load resouces such as images, audios only at a time when they are needed. This helps to mitigate the problem of insuffcient memory instead of loading all your resources at once. In addition, if you end up not using the resources, loading it wastes memory for no purpose.
- Use Core Data or SQLite for large data sets: As referred to by apple: “If your app manipulates large amounts of structured data, store it in a Core Data persistent store or in a SQLite database instead of in a flat file. Both Core Data and SQLite provides efficient ways to manage large data sets without requiring the entire set to be in memory all at once”.
Debugging App Memory
Override dealoc method
One of the good ways to see if certain object or viewcontroller is being deallocated is to override dealoc method.
-(void)dealloc { NSLog(@"viewcontroller is being deallocated"); }
In objective-C, when an object is about to deallocate, it will send a message to dealoc function. By adopting this function, you will see if the object is actually deallocated or not.
Using the debugger and breakpoints
This is quite a fundamental debugging concept when using Xcode IDE to stop the running program at some certain points to investigate thestate of an object. It’s helpful if you can have an idea where the error might appears.
Performing Static Code Analysis
Static analysis is a mechanism where a collection of techniques in IDE are used to analyze your source code to find potential bugs in project such as leaking allocated memory, logic flaws etc. This is a good step you should do before running the app or pulling out instruments to test the application.
- Choose Product > Analyze.
- In the issue navigator, select an analyzer message.
- In the source editor, click the corresponding message.
- Use the pop-up menu in the analysis results bar above the edit area to study the flow path of the flaw.
- Edit the code to fix the flaw.
Using Instruments
Instruments is your best friends when it comes to tracking down problems in your source code; and finding memory problems in your app, such as leaks, abandoned memory, and zombies during runtime. It is a very powerful and flexible performance-analysis and testing tool that ispart of the Xcode tool set. Within the Instruments app, there are many kinds of instruments such as Allocations, Leaks, Core Animation, Energy Diagnostics and Time Profiler. To track memory problems, I recommend that you to go and check out the ‘Allocations instrument and Leaks instrument’.
Apple’s document on Instruments are here
C0nclusion
I hope that the tips above will help you manage memory in your apps more efficiently. If you have any questions, please leave the comments below. Thanks!
Reference
Apple – About Memory Management
7 foolproof tips for iOS memory management using Swift and Objective-C
Memory Management Policy (Non-ARC the old way)
Automatic Reference Counting Swift (examples of cycles) Objective-C Memory Management Essentials – Gibson Tang & Maxim Vasilkov
Brought to you by the RobustTechHouse team. If you like our articles, please also check out our Facebook page.
Some truly wonderful content on this web site , appreciate it for contribution.