Out of Memory (OOM) Terminations¶
What is an OOM?¶
Crashlytics reports crashes caused by signals, Mach exceptions and uncaught C++/Obj-C exceptions. However, these are not the only reasons your app may unexpectedly exit. As you use RAM on an end user’s device, the operating system can decide to reclaim that memory for other processes and terminate your app–we call this an Out of Memory (OOM) termination. Unfortunately, we cannot make use of the same mechanisms to capture OOMs as we do for crashes.
How do we detect OOMs?¶
Every time we see an app launch, we systematically eliminate possible reasons for a previous termination. Only when we rule out some directly observable reasons–a crash, the user force-quitting the app, or the OS or app updating–do we conclude an OOM has occurred. We only report the OOM if the app was in the foreground before the second launch. This system is partially modelled after the one described by Ali Ansari and Grzegorz Pstrucha in this blog post: https://code.facebook.com/posts/1146930688654547/reducing-fooms-in-the-facebook-ios-app/.
If you call exit in your app, that termination will affect your OOM-free session counts. Calling exit is explicitly discouraged by Apple (https://developer.apple.com/library/ios/qa/qa1561/_index.html).
How do OOMs and OOM sessions relate to Answers sessions?¶
Answers sessions are based pairing foreground and background events, whereas OOM sessions are based on launches–they are not directly comparable. See (https://docs.fabric.io/apple/answers/answers-metrics.html#sessions) for more information about Answers sessions.
Because OOMs cause app termination without reporting transitions to the background state, Answers does not record a session for that launch. This typically results in inverse proportions between OOM and Answers session counts.
How should you go about debugging OOMs?¶
Avoiding OOMs is all about improving the memory performance of your app. Apple focuses heavily on app performance, and provides tools as well as tutorials on how to use them. If you suspect your app is being terminated due to memory pressure, we recommend trying the following:
- Xcode’s static analyzer can find some leaks (make sure CLANG_STATIC_ANALYZER_MODE is set to deep when run)
- the Allocations and Leaks instruments can help find more leaks, as well as retain cycles, and characterize the memory footprint of your app (https://developer.apple.com/videos/play/wwdc2012/409/, https://developer.apple.com/videos/play/wwdc2015/230/)
- the System Trace instrument may find situations where interacting with other system components contributes to memory pressure (https://developer.apple.com/videos/play/wwdc2016/411/)
Some new tools became available starting in Xcode 8:
- the Memory Debugger replaces some functionality from the Allocations and Leaks instruments (https://developer.apple.com/videos/play/wwdc2016/410/)
- the Thread Sanitizer can help detect data issues that may arise from race conditions, abandoned threads or deadlocks (https://developer.apple.com/videos/play/wwdc2016/412/)
You can also implement applicationDidReceiveMemoryWarning in your app delegate to be notified when your app places too much pressure on system memory or subscribe to the UIApplicationDidReceiveMemoryWarningNotification notification. Implement didReceiveMemoryWarning in any view controller subclass for more targeted notifications, or if you have an idea of a particular view controller that may cause problems (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/#//apple_ref/occ/intfm/UIApplicationDelegate/applicationDidReceiveMemoryWarning:).