Learn best practices for using memory efficiently in iOS and tvOS.
Efficient memory usage is a critical consideration for resource-intensive Metal-based apps in iOS and tvOS. Apps should use as little memory as possible, making more memory available for other apps and system services.
iOS and tvOS monitor your app’s total memory usage at runtime, and if the amount exceeds a predetermined limit, the system terminates your app. This limit varies by device model, so be sure to test your app on all supported devices.
Understand Changes in Memory Accounting
The accounting for purgeable, nonvolatile memory has changed in iOS 12 and tvOS 12. In iOS 11 and tvOS 11, allocations with this memory storage mode—commonly used by Metal apps to store buffers, textures, and state objects—weren't counted toward an app’s memory limit and weren't presented in tools like Xcode memory gauge. It was possible for an app’s actual memory usage to exceed certain predetermined memory limits without being terminated.
In iOS 12 and tvOS 12, if an app is built with the iOS 12 or tvOS 12 SDK, such allocations are counted toward the app’s memory usage limit. As a result, the system can now more accurately monitor an app’s total memory usage. However, if such an app previously exceeded the limit, it's now likely to be terminated on devices running iOS and tvOS versions 12 and later.
Starting March 27, 2019, all new apps and app updates for iPhone or iPad, including universal apps, must be built with the iOS 12.1 or later SDK and support iPhone XS Max or iPad Pro (12.9-inch) (3rd generation). If you have difficulty reducing your app’s memory requirements, contact us to request an entitlement for your app to use iOS 11–style memory accounting.
Optimize Memory Usage in Your Metal App
Here are some tips for understanding how your Metal app is using memory, and best practices for reducing memory usage.
Use Xcode 10 to measure memory consumption. Build your app with the iOS 12 or tvOS 12 SDK, then use Xcode memory gauge to observe your app’s total memory footprint during execution. You can get more detail by doing an Instruments trace, Capturing a Frame Using Xcode, or using the memory graph tool.
Make your assets as small as possible. Avoid loading a large resource when a smaller one will do. Use compressed texture formats. Load lower-resolution textures when running on memory-constrained devices. Consider reducing the fidelity of 3D models and compressing per-vertex data.
Simplify memory-intensive special effects. Some effects, like shadows or motion blur, require large offscreen buffers for temporary image data. Consider lowering the resolution of these image buffers or applying fewer effects when running on memory-constrained devices.
Avoid loading unused resources. Xcode can help you identify Metal objects that aren't in use. After Capturing a Frame Using Xcode, select the all-resources view of the assistant editor and change the search filter to show only used resources. Then invert the filter by choosing Does Not Contain from the filter menu to see any unused resources.
Designate resources as volatile when possible. Use
set for textures and buffers whose underlying memory could be discarded under low-memory conditions, and subsequently recreated or reloaded as needed. This allows your app to keep a cache of idle resources in memory while avoiding counting them toward the memory limit.
Use memoryless texture storage for temporary render targets.
MTLStorage avoids allocating regular system memory, allowing apps to store the contents of temporary render targets directly in tile memory on the GPU.
Use Metal resource heaps.
MTLHeap allows multiple Metal resources to be backed by the same memory allocation. For instance, you can use resource heaps when transient resources are produced and consumed for each frame but aren't all used together. Those not used together can share the same memory, backed by a heap.