ローメモリ キラー デーモン(Imkd)

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

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

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

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

ユーザー空間 lmkd

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

強制終了戦略

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

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

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

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

ユーザー空間 lmkd の使用

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

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
    CONFIG_MEMCG=y
    CONFIG_MEMCG_SWAP=y
    

プレッシャー ストール情報(PSI)

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)にしてコンパイルする必要があります。

lmkd の設定

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

プロパティ 用途 デフォルト
ro.config.low_ram 低メモリデバイスと高性能デバイスのいずれかを選択します。 false
ro.lmk.use_psi vmpressure イベントではなく)PSI モニターを使用します。 true
ro.lmk.use_minfree_levels 空きメモリとファイル キャッシュのしきい値を使用して、プロセスの強制終了を決定します(つまり、カーネル内の lowmemorykiller ドライバの機能に一致します)。 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