On the Android platform, the system tries to use as much system memory (RAM) as possible and performs various memory optimizations to free up space when needed. These optimizations can have a negative effect on your game, either by slowing it down or killing it altogether. You can learn more about these optimizations in the topic Memory allocation among processes.
This page explains the steps you can take to avoid low memory conditions affecting your game.
Respond to onTrimMemory()
The system uses
onTrimMemory()
to notify your app that memory is running low and the app may be killed. Many
times, this is the only warning your app gets. This callback has high latency
relative to the
low-memory killer (LMK),
so it is critical to respond quickly to the callback.
In response to this callback, reduce the speed, number, and size of allocations.
onTrimMemory()
passes a constant indicating the severity, but you should
respond to the first warning as it’s possible to allocate more quickly than what
onTrimMemory()
can react to.
Kotlin
class MainActivity : AppCompatActivity(), ComponentCallbacks2 { override fun onTrimMemory(level: Int) { when (level) { ComponentCallbacks2.TRIM_MEMORY_MODERATE, ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW, ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL -> // Respond to low memory condition else -> Unit } } }
Java
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 { public void onTrimMemory(int level) { switch (level) { case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE: // Respond to low memory condition break; case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW: // Respond to low memory condition break; case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL: // Respond to low memory condition break; default: break;
C#
using UnityEngine; using System.Collections; using System.Collections.Generic; class LowMemoryTrigger : MonoBehaviour { private void Start() { Application.lowMemory += OnLowMemory; } private void OnLowMemory() { // Respond to low memory condition (e.g., Resources.UnloadUnusedAssets()) } }
Use the Memory Advice API beta
The Memory Advice API was developed as an
alternative to onTrimMemory that has much higher recall and precision at
predicting impending LMKs. The API achieves this by estimating the amount of
memory resources that are in use, and then notifying the app when certain
thresholds are exceeded. The API can also report the estimated percentage of
memory use directly to your app. You can use the Memory Advice API as an
alternative to
onTrimMemory
events for the purpose of memory management.
To use the Memory Advice API use the getting started guide.
Be conservative with memory budgets
Budget memory conservatively to avoid running out of memory. Some items to consider include the following:
- Size of physical RAM: Games often use between ¼ and ½ of the physical RAM amount on the device.
- Maximum zRAM size: More zRAM means the game potentially has more memory
to allocate. This amount can vary based on device; look for
SwapTotal
in/proc/meminfo
to find this value. - Memory usage of the OS: Devices that designate more RAM to system processes leave less memory for your game. The system kills your game's process before it kills system processes.
- Memory usage of installed apps: Test your game on devices that have many apps installed. Social media and chat apps need to run constantly and affect the amount of free memory.
If you can’t commit to a conservative memory budget, take a more flexible
approach. If the system runs into low memory issues, reduce the amount of memory
that the game is using. For example, allocate lower-resolution textures or store
fewer shaders in response to onTrimMemory()
. This dynamic approach to memory
allocation requires more work from the developer, especially in the game design
phase.
Avoid thrashing
Thrashing occurs when free memory is low, but not low enough to kill the game.
In this situation, kswapd
has reclaimed pages that the game still needs, so it
tries to reload the pages from memory. There isn’t enough space, so the pages
keep getting swapped out (continuous swapping).
System tracing reports this situation as a thread
where kswapd
runs continuously.
One symptom of thrashing is long frame times - possibly a second or more. Reduce the memory footprint of the game to resolve this situation.
Use available tools
Android has a collection of tools to assist in understanding how the system manages memory.
Meminfo
This tool collects memory statistics to show how much PSS memory was allocated and the categories for which it was used.
Print the meminfo statistics in one of the following ways:
- Use the command
adb shell dumpsys meminfo package-name
. - Use the
MemoryInfo
call from the Android Debug API.
The PrivateDirty
statistic shows the
amount of RAM inside the process that can not be paged to disk and is not shared
with any other processes. The bulk of this amount becomes available to the
system when that process is killed.
Memory tracepoints
Memory tracepoints track the amount of RSS memory your game is using. Calculating RSS memory usage is much faster than calculating PSS usage. Because it’s faster to calculate, RSS shows finer granularity on changes in the memory size for more accurate measurements of peak memory usage. Therefore, it's easier to notice peaks that could cause the game to run out of memory.
Perfetto and long traces
Perfetto is a suite of tools for collecting performance and memory information on a device and displaying in a web-based UI. It supports arbitrarily long traces so you can view how RSS changes over time. You can also issue SQL queries on the data it produces for offline processing. Enable long traces from the System Tracing app. Make sure the memory:Memory category is enabled for the trace.
heapprofd
heapprofd
is a memory tracking tool
that’s part of Perfetto. This tool can help you find memory leaks by showing
where memory was allocated using malloc
. heapprofd
can be started using a
Python script, and because the tool has low overhead, it doesn't affect
performance like other tools such as Malloc Debug.
bugreport
bugreport
is a logging tool for finding out whether or not your game crashed
because it ran out of memory. The tool's output is much more detailed than using
logcat. It’s useful for memory debugging because it shows if your game crashed
because it ran out of memory or if it was killed by the LMK.
For more information, see Capture and read bug reports.