ローメモリ キラーデーモン

Android のローメモリ キラー デーモン(lmkd)プロセスは、実行中の Android システムのメモリ状態をモニタリングし、必要最小限のプロセスを停止してシステムのパフォーマンスを許容レベルに維持することでハイメモリ プレッシャーに対応します。

メモリ プレッシャーについて

複数のプロセスを並行して実行している Android システムでは、システムメモリを使い果たし、より多くのメモリを必要とするプロセスで顕著な遅延が発生する場合があります。システムのメモリが不足している状態であるメモリ プレッシャーでは、重要でないプロセスの抑制または強制終了を行う、重要でないキャッシュされたリソースの解放をプロセスにリクエストする、などによって、Android がメモリを解放する(プレッシャーを軽減する)必要があります。

これまで Android では、ハードコードされた値に依存する厳格なメカニズムである、カーネル内のローメモリ キラー(LMK)ドライバを使用して、システムメモリ プレッシャーを監視していました。カーネル 4.12 の時点で、LMK ドライバは上流のカーネルから削除されており、ユーザー空間 lmkd がメモリのモニタリングとプロセス強制終了タスクを実行します。

プレッシャーのストールに関する情報

Android 10 以降では、メモリ プレッシャーの検出にカーネル プレッシャー ストール情報(PSI)モニターを使用する、新しい lmkd モードがサポートされています。上流カーネルの PSI パッチセット(4.9 カーネルと 4.14 カーネルに移植)は、メモリ不足によってタスクが遅延する時間を測定します。こうした遅延はユーザー エクスペリエンスに直接影響するため、メモリ プレッシャーの重大度を判断するための便利な指標となります。上流カーネルには PSI モニターも含まれており、特権ユーザー空間プロセス(lmkd など)でこうした遅延のしきい値を指定でき、しきい値に達したときはカーネルからのイベントを登録できます。

PSI モニターと vmpressure シグナル

vmpressure シグナル(メモリ プレッシャー検出のためにカーネルによって生成され、lmkd によって使用されます)には多くの場合、誤検出が多数含まれるため、lmkd は、メモリが実際のプレッシャー下にあるかどうかを判断するためにフィルタリングを行う必要があります。その結果、不要な lmkd ウェイクアップが発生し、計算リソースがさらに使用されます。PSI モニターを使用すると、メモリ プレッシャーの検出がより正確になり、フィルタリングのオーバーヘッドが最小限になります。

PSI モニターの使用

vmpressure イベントではなく PSI モニターを使用するには、ro.lmk.use_psi プロパティを設定します。デフォルトは true で、PSI は lmkd のメモリ プレッシャー検出のデフォルト メカニズムをモニタリングします。PSI モニターにはカーネル サポートが必要なため、カーネルは PSI 移植パッチを含む必要があり、PSI サポートを有効(CONFIG_PSI=y)にしてコンパイルする必要があります。

カーネル内の LMK ドライバの欠点

Android は、次のような問題により、LMK ドライバのサポートを終了しました。

  • 低 RAM デバイスは頻繁にチューニングする必要があり、ファイルベースのアクティブなページ キャッシュが大量にあるワークロードではパフォーマンスが低下します。このパフォーマンスの低下によりスラッシングが発生し、処理が終了しません。
  • LMK カーネル ドライバは空きメモリの限度の影響を受けますが、メモリ プレッシャーに基づくスケーリングはありません。
  • 設計が柔軟性に欠けるため、パートナーはドライバが自社のデバイスで動作するようにドライバをカスタマイズしていました。
  • LMK ドライバは、slab shrinker API に接続していましたが、この API はターゲットの検索や終了などの負荷のかかるオペレーション用には設計されていないため、vmscan プロセスが遅くなっていました。

ユーザー空間 lmkd

ユーザー空間 lmkd はカーネル内のドライバと同じ機能を実装していますが、メモリ プレッシャーを検出して推定するために既存のカーネル メカニズムを使用します。このようなメカニズムには、カーネルによって生成された vmpressure イベントまたはプレッシャー ストール情報(PSI)モニターを使用してメモリ プレッシャー レベルに関する通知を取得したり、メモリ cgroup 機能を使用してプロセスの重要度に基づいて各プロセスに割り当てられるメモリリソースを制限するなどの機能があります。

Android 10 でユーザー空間 lmkd を使用する

Android 9 以降では、カーネル内の LMK ドライバが検出されない場合、ユーザー空間 lmkd が有効になります。ユーザー空間 lmkd はメモリ cgroup のカーネル サポートを必要とするため、カーネルは次の設定でコンパイルする必要があります。

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

強制終了戦略

ユーザー空間 lmkd は、vmpressure イベントまたは PSI モニター、その重大度、その他のヒント(スワップ使用率など)に基づき、強制終了戦略をサポートします。強制終了戦略は、低メモリデバイスと高性能デバイスで異なります。

  • 低メモリデバイスでは、システムは通常の動作モードで、高いメモリ プレッシャーに耐える必要があります。
  • 高性能デバイスでは、メモリ プレッシャーを異常な状況として認識し、全体的なパフォーマンスに影響が及ぶ前に修正する必要があります。

強制終了戦略は、ro.config.low_ram プロパティを使用して設定できます(詳細については、低 RAM 設定をご覧ください)。

ユーザー空間 lmkd は、カーネル内の LMK ドライバと同じ戦略(つまり空きメモリとファイル キャッシュのしきい値)を使用して強制終了の決定を行う、従来のモードもサポートしています。従来のモードを有効にするには、ro.lmk.use_minfree_levels プロパティを true に設定します。

lmkd の設定

次のプロパティを使用して、特定のデバイスに lmkd を設定します。

プロパティ 用途 デフォルト
ro.config.low_ram デバイスが低 RAM デバイスと高性能デバイスのどちらであるかを指定します。 false
ro.lmk.use_psi PSI モニターを使用します(vmpressure イベントは使用しません)。 true
ro.lmk.use_minfree_levels 空きメモリとファイル キャッシュのしきい値を使用して、プロセスの強制終了を決定します(つまり、カーネル内の LKM ドライバの機能に一致します)。 false
ro.lmk.low vmpressure レベルが低い場合に強制終了できるプロセスの最小 oom_adj スコア。 1001
(無効)
ro.lmk.medium vmpressure レベルが中程度の場合に強制終了できるプロセスの最小 oom_adj スコア。 800
(キャッシュされたサービスまたは必須でないサービス)
ro.lmk.critical vmpressure レベルが重大の場合に強制終了できるプロセスの最小 oom_adj スコア。 0
(任意のプロセス)
ro.lmk.critical_upgrade 重大レベルへのアップグレードを有効にします。 false
ro.lmk.upgrade_pressure システムがスワップしすぎるためにレベルがアップグレードされる最大 mem_pressure 100
(無効)
ro.lmk.downgrade_pressure 十分な空きメモリがまだ使用可能であるために vmpressure イベントが無視される最小 mem_pressure 100
(無効)
ro.lmk.kill_heaviest_task 任意の適格タスク(迅速な決定)と比較して最も重い適格タスク(最良の決定)を強制終了します。 true
ro.lmk.kill_timeout_ms 追加の強制終了が行われない場合の強制終了後の時間(ミリ秒)。 0
(無効)
ro.lmk.debug lmkd デバッグログを有効にします。 false

デバイス設定の例:

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

Android 11 のユーザー空間 lmkd

Android 11 では新しい強制終了戦略が導入され、lmkd が改善されています。強制終了戦略は、Android 10 で導入されたメモリ プレッシャー検出に、PSI メカニズムを使用します。Android 11 の lmkd では、メモリ不足とパフォーマンスの低下を防ぐために、メモリリソースの使用量レベルとスラッシングが考慮されます。この強制終了戦略は、以前の戦略に代わるもので、高性能デバイスと低 RAM(Android Go)デバイスの両方で使用できます。

カーネルの要件

Android 11 デバイスの場合、lmkd には次のカーネル機能が必要です。

  • PSI パッチを追加し、PSI(Android 共通カーネル 4.9、4.14、4.19)で利用可能なバックポートを有効にする。
  • PIDFD のサポートパッチ(Android 共通カーネル 4.9、4.14、4.19 で使用可能なバックポート)を追加する。
  • 低 RAM デバイスの場合はメモリ cgroup を追加する。

カーネルは、次の設定でコンパイルする必要があります。

CONFIG_PSI=y

Android 11 で lmkd を設定する

Android 11 のメモリ強制終了戦略では、以下の調整ノブとデフォルトがサポートされています。これらの機能は、高性能デバイスと低 RAM デバイスの両方で機能します。

プロパティ 用途 デフォルト
高性能 低 RAM
ro.lmk.psi_partial_stall_ms メモリ不足の通知をトリガーする部分 PSI のストールのしきい値(ミリ秒単位)。デバイスでメモリ プレッシャー通知の受信が遅すぎる場合は、この値を下げて通知が早くトリガーされるようにします。メモリ プレッシャー通知が必要以上にトリガーされる場合は、この値を増やしてデバイスがノイズに反応しにくくなるようにします。 70 200
ro.lmk.psi_complete_stall_ms 重要なメモリ通知をトリガーする完全 PSI のストールのしきい値(ミリ秒単位)。デバイスで重要なメモリ プレッシャー通知の受信が遅すぎる場合は、この値を下げて通知が早くトリガーされるようにします。重要なメモリ プレッシャー通知が必要以上にトリガーされる場合は、この値を増やしてデバイスがノイズに反応しにくくなるようにします。 700
ro.lmk.thrashing_limit ファイル バックアップのページキャッシュ サイズの合計に対する、ワーキング セットの再試行の最大割合(パーセント単位)。ワーキング セットがこの値より上にあると、システムはページキャッシュをスラッシングしたと見なされます。メモリ プレッシャーの間にデバイスのパフォーマンスに影響が生じる場合は、値を引き下げてスラッシングを制限します。スラッシングが原因でデバイスのパフォーマンスが必要以上に強制終了される場合は、より多くのスラッシングを許可するように値を増やします。 100 30
ro.lmk.thrashing_limit_decay スラッシングのしきい値の減衰。システムが回復しない場合(強制終了後も含む)にしきい値を下げるために使用される元のしきい値の割合として表されます。連続スラッシングによって不要な強制終了が生成される場合は、この値を小さくします。強制終了後の連続スラッシングへの反応が遅すぎる場合は、この値を増やします。 10 50
ro.lmk.swap_util_max スワップされたメモリの最大量。スワップ可能なメモリ全体に対する割合として表されます。スワップされたメモリがこの上限を超えると、スワップ可能メモリの大部分がシステムによってスワップされ、まだプレッシャーが解消されていないことを表します。 これは、スワップ不可能な割り当てがメモリ プレッシャーを生成している場合に発生することがあります。このとき、スワップ可能なメモリのほとんどがスワップされているため、この状態は解消できません。デフォルト値は 100 です。この値を適用すると、このチェックが実質的に無効になります。スワップ使用率が高く、空きスワップレベルが ro.lmk.swap_free_low_percentage まで下がらない状態で、メモリ プレッシャーの間にデバイスのパフォーマンスに影響が生じる場合は、値を引き下げてスワップ使用率を制限します。 100 100

以下の従来の調整ノブも、新しい強制終了戦略で機能します。

プロパティ 用途 デフォルト
高性能 低 RAM
ro.lmk.swap_free_low_percentage 空きスワップのレベル。スワップ領域全体に対するパーセンテージとして表されます。「lmkd」はこの値を、システムのスワップ領域が不足していると判断するためのしきい値として使用します。スワップ領域に十分余裕がある場合でも「lmkd」が強制終了された場合は、その割合を下げます。「lmkd」の強制終了が遅すぎる場合は、OOM の強制終了を発生させることで割合を増やします。 20 10
ro.lmk.debug これにより、「lmkd」デバッグログが有効になります。チューニング中にデバッグを有効にします。 false