The Android low memory killer daemon (lmkd
) process monitors the memory
state of a running Android system and reacts to high memory pressure by killing
the least essential processes to keep the system performing at acceptable
levels.
About memory pressure
An Android system running multiple processes in parallel may encounter situations when system memory is exhausted and processes that require more memory experience noticeable delays. Memory pressure, a state in which the system is running short on memory, requires Android to free memory (to alleviate the pressure) by throttling or killing unimportant processes, requesting processes to free noncritical cached resources, and so on.
Historically, Android monitored system memory pressure using an in-kernel
low memory killer (LMK) driver, a rigid mechanism that depends on hard-coded
values. As of kernel 4.12, the LMK driver is removed from the upstream
kernel and the userspace lmkd
performs memory monitoring and process killing
tasks.
Pressure stall information
Android 10 and higher support a new lmkd
mode that
uses kernel pressure stall information (PSI) monitors for memory pressure
detection. The PSI patchset in the upstream kernel (backported to 4.9 and 4.14
kernels) measures the amount of time that tasks are delayed as a result of
memory shortages. As these delays directly affect user experience, they
represent a convenient metric for determining memory pressure severity. The
upstream kernel also includes PSI monitors that allow privileged userspace
processes (such as lmkd
) to specify thresholds for these delays and to
subscribe to events from the kernel when a threshold is breached.
PSI monitors versus vmpressure signals
Because the vmpressure
signals (generated by the kernel for memory
pressure detection and used by lmkd
) often include numerous false positives,
lmkd
must perform filtering to determine if the memory is under real pressure.
This results in unnecessary lmkd
wakeups and the use of additional
computational resources. Using PSI monitors results in more accurate memory
pressure detection and minimizes filtering overhead.
Use PSI monitors
To use PSI monitors instead of vmpressure
events, configure the
ro.lmk.use_psi
property. The default is true
, making PSI monitors the
default mechanism of memory pressure detection for lmkd
. Because PSI monitors
require kernel support, the kernel must include the PSI backport patches and be
compiled with PSI support enabled (CONFIG_PSI=y
).
Drawbacks of in-kernel LMK driver
Android deprecates the LMK driver due to a number of issues, including:
- Low-RAM devices had to be tuned aggressively, and even then would perform poorly on workloads with large file-backed active pagecache. The poor performance resulted in thrashing and no kills.
- The LMK kernel driver relied on free-memory limits, with no scaling based on the memory pressure.
- Because of the rigidity of the design, partners often customized the driver so that it would work on their devices.
- The LMK driver hooked into the slab shrinker API, which wasn't
designed for heavy operations such as searching for targets and killing
them, which slowed down the
vmscan
process.
Userspace lmkd
The userspace lmkd
implements the same functionality as the in-kernel driver
but uses existing kernel mechanisms to detect and estimate memory pressure. Such
mechanisms include using kernel-generated vmpressure
events or pressure stall
information (PSI) monitors to get notifications about memory pressure levels,
and using memory cgroup features to limit the memory resources allocated to each
process based on process importance.
Use userspace lmkd in Android 10
In Android 9 and higher, userspace lmkd
activates if
an in-kernel LMK driver isn't detected. Because userspace lmkd
requires kernel support for memory cgroups, the kernel must be compiled with the
following configuration settings:
CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
Kill strategies
Userspace lmkd
supports kill strategies based on vmpressure
events or PSI
monitors, their severity, and other hints such as swap utilization. Kill
strategies differ between low-memory and high-performance devices:
- On low-memory devices, the system should tolerate higher memory pressure as a normal mode of operation.
- On high-performance devices, memory pressure should be viewed as an abnormal situation and fixed before it affects overall performance.
You can configure the kill strategy using the ro.config.low_ram
property. For
details, see Low ram
configuration.
Userspace lmkd
also supports a legacy mode in which it makes kill decisions
using the same strategies as the in-kernel LMK driver (that is, free
memory and file cache thresholds). To enable legacy mode, set the
ro.lmk.use_minfree_levels
property to true
.
Configure lmkd
Configure lmkd
for a specific device using the following properties.
Property | Use | Default |
---|---|---|
ro.config.low_ram
|
Specify if the device is a low-RAM or high-performance device. | false
|
ro.lmk.use_psi |
Use PSI monitors (instead of vmpressure events). |
true |
ro.lmk.use_minfree_levels
|
Use free memory and file cache thresholds for making process kill decisions (that is, match the functionality of the in-kernel LMK driver). | false
|
ro.lmk.low
|
The minimum oom_adj score for processes eligible to be
killed at low vmpressure level.
|
1001 (disabled) |
ro.lmk.medium
|
The minimum oom_adj score for processes eligible to be
killed at medium vmpressure level.
|
800 (cached or nonessential services) |
ro.lmk.critical
|
The minimum oom_adj score for processes eligible to be
killed at critical vmpressure level.
|
0 (any process) |
ro.lmk.critical_upgrade
|
Enable upgrade to critical level. | false
|
ro.lmk.upgrade_pressure
|
The maximum mem_pressure at which the level is upgraded
because the system is swapping too much.
|
100 (disabled) |
ro.lmk.downgrade_pressure
|
The minimum mem_pressure at which a vmpressure
event is ignored because enough free memory is still available.
|
100 (disabled) |
ro.lmk.kill_heaviest_task
|
Kill the heaviest eligible task (best decision) versus any eligible task (fast decision). | false
|
ro.lmk.kill_timeout_ms
|
Duration in milliseconds after a kill when no additional kill will be done. | 0 (disabled) |
ro.lmk.debug
|
Enable lmkd debug logs.
|
false
|
Example device configuration:
PRODUCT_PROPERTY_OVERRIDES += \
ro.lmk.low=1001 \
ro.lmk.medium=800 \
ro.lmk.critical=0 \
ro.lmk.critical_upgrade=false \
ro.lmk.upgrade_pressure=100 \
ro.lmk.downgrade_pressure=100 \
ro.lmk.kill_heaviest_task=true
Userspace lmkd in Android 11
Android 11 improves the lmkd
by introducing a new
killing strategy. The killing strategy uses a PSI mechanism for memory pressure
detection introduced in Android 10. lmkd
in
Android 11 accounts for memory resource use levels
and thrashing to prevent memory starvation and performance degradation.
This killing strategy replaces previous strategies and can be used on both
high-performance and low-RAM (Android Go) devices.
Kernel requirements
For Android 11 devices, lmkd
requires the following kernel features:
- Include PSI patches and enable PSI (backports available in Android common kernels 4.9, 4.14, and 4.19).
- Include PIDFD support patches (backports available in Android common kernels 4.9, 4.14, and 4.19).
- For low-RAM devices, include memory cgroups.
The kernel must be compiled with the following configuration settings:
CONFIG_PSI=y
Configure lmkd in Android 11
The memory killing strategy in Android 11 supports the tuning knobs and defaults listed below. These features work on both high-performance and low-RAM devices.
Property | Use | Default | |
---|---|---|---|
High performance | Low RAM | ||
ro.lmk.psi_partial_stall_ms |
The partial PSI stall threshold, in milliseconds, for triggering low memory notification. If the device receives memory pressure notifications too late, decrease this value to trigger earlier notifications. If memory pressure notifications trigger unnecessarily, increase this value to make the device less sensitive to noise. | 70 |
200 |
ro.lmk.psi_complete_stall_ms |
The complete PSI stall threshold, in milliseconds, for triggering critical memory notifications. If the device receives critical memory pressure notifications too late, decrease this value to trigger earlier notifications. If critical memory pressure notifications trigger unnecessarily, increase this value to make the device less sensitive to noise. | 700 |
|
ro.lmk.thrashing_limit |
The max amount of workingset refaults as a percentage of the total file-backed pagecache size. Workingset refaults above this value mean that the system is considered to be thrashing its pagecache. If the performance of the device is affected during memory pressure, decrease the value to limit thrashing. If the performance of the device is killed unnecessarily for thrashing reasons, increase the value to allow more thrashing. | 100 |
30 |
ro.lmk.thrashing_limit_decay |
The thrashing threshold decay expressed as a percentage of the original threshold used to lower the threshold when the system doesn’t recover, even after a kill. If continuous thrashing produces unnecessary kills, decrease the value. If the response to continuous thrashing after a kill is too slow, increase the value. | 10 |
50 |
ro.lmk.swap_util_max |
The max amount of swapped memory as a percentage of the total swappable
memory. When swapped memory grows over this limit, it means that the
system swapped most of its swappable memory and is still under pressure.
This can happen when non-swappable allocations are generating memory
pressure which can't be relieved by swapping because most of the swappable
memory is already swapped out. The default value is 100, which effectively
disables this check. If the performance of the device is affected during
memory pressure while swap utilization is high and the free swap level
isn't dropping to ro.lmk.swap_free_low_percentage , decrease
the value to limit swap utilization. |
100 |
100 |
The following old tuning knobs also work with the new killing strategy.
Property | Use | Default | |
---|---|---|---|
High performance | Low RAM | ||
ro.lmk.swap_free_low_percentage |
The level of free swap as a percentage of the total swap space. `lmkd` uses this value as a threshold for when to consider the system as swap space starved. If `lmkd` kills while there's too much space in swap, decrease the percentage. If `lmkd` kills happen too late, allowing OOM kills to happen, increase the percentage. | 20 |
10 |
ro.lmk.debug |
This enables `lmkd` debug logs. Enable debug while tuning. | false |