IPhone OS 内存警告。不同的级别意味着什么?

关于在 iPhone OS 设备上管理内存的黑魔法: 不同级别的内存警告意味着什么。一级?二级?刻度盘转到11了吗?

背景: 经过一段长时间的内存压力测试期——包括用 iPod 音乐播放器运行我的 iPad 应用程序,我倾向于忽略我收到的随机而罕见的内存警告。我的应用程序 永远不会崩溃了。永远不会。我的应用程序是无泄漏的。而且,那些表情包的警告似乎并不重要。

谢谢,
道格

58630 次浏览

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:

  1. Warning (not-normal) — Relaunch, or delay auto relaunch of nonessential background apps e.g. Mail.
  2. Urgent — Quit all background apps, e.g. Safari and iPod.
  3. 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.