Regarding the black art of managing memory on iPhone OS devices: what do the different levels of memory warning mean. Level 1? Level 2? Does the dial go to 11?
Context: After an extensive memory stress testing period - including running my iPad app with the iPod music player app playing, I am inclined to ignore the random yet infrequent memory warnings I am receiving. My app never crashes. Ever. My app is leak free. And, well, the mems warnings just don't seem to matter.
Thanks,
Doug
Basically the warnings mean that the device is running low on memory, and that, "If you could please free some memory you aren't actively using that'd be swell!". If your memory management is tight, and you have no objects that could practically be discarded, just pass the message along and ignore it.
Memory level warnings are logged by SpringBoard. As an app developer you don't need to care about it. Just responding to -{application}didReceiveMemoryWarning
is enough.
There are 4 levels of warnings (0 to 3). These are set from the kernel memory watcher, and can be obtained by the not-so-public function OSMemoryNotificationCurrentLevel()
.
typedef enum {
OSMemoryNotificationLevelAny = -1,
OSMemoryNotificationLevelNormal = 0,
OSMemoryNotificationLevelWarning = 1,
OSMemoryNotificationLevelUrgent = 2,
OSMemoryNotificationLevelCritical = 3
} OSMemoryNotificationLevel;
How the levels are triggered is not documented. SpringBoard is configured to do the following in each memory level:
- Warning (not-normal) — Relaunch, or delay auto relaunch of nonessential background apps e.g. Mail.
- Urgent — Quit all background apps, e.g. Safari and iPod.
- Critical and beyond — The kernel will take over, probably killing SpringBoard or even reboot.
Killing the active app (jetsam) is not handled by SpringBoard, but launchd
.
From OSMemoryNotification.h,
/*
** Threshold values for notifications
*/
typedef enum {
OSMemoryNotificationLevelAny = -1,
OSMemoryNotificationLevelNormal = 0,
OSMemoryNotificationLevelWarning = 1,
OSMemoryNotificationLevelUrgent = 2,
OSMemoryNotificationLevelCritical = 3
} OSMemoryNotificationLevel;
totoal 5 levels of memory warning (-1,3).
Regarding Memory Level warning description, @KennyTM's answer is excellent.
I want to add several related points which may help PM and others.
What should you do when having Memory Level Warning?
Upon receiving any of these warnings, your handler method should respond by immediately freeing up any unneeded memory. For example, the default behavior of the UIViewController class is to purge its view if that view is not currently visible; subclasses can supplement the default behavior by purging additional data structures. An app that maintains a cache of images might respond by releasing any images that are not currently onscreen.
How to observe Memory Level warning?
From http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/PerformanceTuning/PerformanceTuning.html
When the system dispatches a low-memory warning to your app, respond immediately. iOS notifies all running apps whenever the amount of free memory dips below a safe threshold. (It does not notify suspended apps.) If your app receives this warning, it must free up as much memory as possible. The best way to do this is to remove strong references to caches, image objects, and other data objects that can be recreated later.
UIKit provides several ways to receive low-memory warnings, including the following:
- Implement the applicationDidReceiveMemoryWarning: method of your app
delegate.
- Override the didReceiveMemoryWarning method in your custom
UIViewController subclass.
- Register to receive the
UIApplicationDidReceiveMemoryWarningNotificationnotification.
How to Reduce Your App’s Memory Footprint?
- Eliminate memory leaks.
- Make resource files as small as possible.
- Use Core Data or SQLite for large data sets.
- Load resources lazily.
- Build your program using the Thumb option.
Details at http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/PerformanceTuning/PerformanceTuning.html
How to allocate memory wisely?
- Reduce your use of autoreleased objects : With automatic reference
counting (ARC), it is better to alloc/init objects and let the
compiler release them for you at the appropriate time. This is true
even for temporary objects that in the past you might have
autoreleased to prevent them from living past the scope of the
current method.
- Impose size limits on resources : Avoid loading a large resource file
when a smaller one will do. Instead of using a high-resolution image,
use one that is appropriately sized for iOS-based devices. If you
must use large resource files, find ways to load only the portion of
the file that you need at any given time. For example, rather than
load the entire file into memory, use the mmap and munmap functions
to map portions of the file into and out of memory. For more
information about mapping files into memory.
- Avoid unbounded problem sets : Unbounded problem sets might require
an arbitrarily large amount of data to compute. If the set requires
more memory than is available, your app may be unable to complete the
calculations. Your apps should avoid such sets whenever possible and
work on problems with known memory limits.