Low memory killer daemon

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:


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
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
ro.lmk.downgrade_pressure The minimum mem_pressure at which a vmpressure event is ignored because enough free memory is still available. 100
ro.lmk.kill_heaviest_task Kill the heaviest eligible task (best decision) versus any eligible task (fast decision). true
ro.lmk.kill_timeout_ms Duration in milliseconds after a kill when no additional kill will be done. 0
ro.lmk.debug Enable lmkd debug logs. false

Example device configuration:

    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 \

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:


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