Android oom メカニズムの簡単な分析

この記事は主に Android11 に基づいて、oom Killer、lowmemorykiller (lmk lmkd)、kswapd に関する Android の知識を整理したものであり、ソース コードは深く分析されていません。

目次

Linux オム

oom_adj、oom_score、oom_score_adj の関係

Android ローメモリキラー(lmk)

アンドロイドアプリのオム

クスワップ

zRAM

kswapd と lmkd

要約する


Linux オム

  • プロセスルールの強制終了: 優先順位に従って、/proc/pid/oom_score (oom_score_adj によって計算) 値が大きいほど、oom キラーによって選択されやすくなります。
  • Linux oom メカニズムはカーネルに組み込まれています
  • 独自のプロセスが簡単に強制終了されないように、ユーザーは oom_score_adj の値を下げることができます。直接 echo -17 > /proc/$PID/oom_adj を実行すると、oom キラーにプロセスを無視させることができます。
  • 具体的な実装メカニズムはoom_kill.cにあります。
  • Linux oom はシステム全体に適用されます。Oom はメモリを割り当てるときにトリガーされます (alloc_page()、メモリを割り当てるときに必ず使用され、メモリはページによって管理されます)。メモリ不足が見つかった場合、oom キラーがトリガーされ、それらのプロセスについては、プロセスを強制終了した後にメモリが回復されます (1 つを強制終了するか、複数のプロセスを強制終了するかはわかりません)。

oom_adj、oom_score、oom_score_adj の関係

  • oom_score: oom_score_adj 値とプロセスによって使用されるメモリ量に基づいてカーネルによって計算された値。後で、oom Killer と lmkd の両方がこの値に基づいてどのプロセスを強制終了するかを決定します。
  • oom_score_adj: 値は -1000---1000 です。値が -1000 の場合、oom キラー (init、surfaceflinger、その他のネイティブ プロセスなど) の管理がオフになります。これと oom_adj は両方とも、強制終了されるプロセスの優先順位を変更するためにカーネルによってユーザー空間に残されたインターフェイスです。AMS は、pid、uid、および adj を LMK_PROCPRIO メッセージ パッケージにカプセル化して lmkd に渡すことで、アプリの adj 値を調整します。これは、lmkd.value を通じて変更されます。
//frameworks/base/services/core/java/com/android/server/am/processlist.java
 public static void setOomAdj(int pid, int uid, int amt) {
        //...
        ByteBuffer buf = ByteBuffer.allocate(4 * 4);
        buf.putInt(LMK_PROCPRIO);
        buf.putInt(pid);
        buf.putInt(uid);
        buf.putInt(amt);
        writeLmkd(buf, null);//通过unix socket写给lmkd
        //...
    }
//system/memory/lmkd/lmkd.cpp
static void ctrl_command_handler(int dsock_idx) {
    //...
        case LMK_PROCPRIO:
        cmd_procprio(packet, nargs, &cred);
        break;
    //...
}

static void cmd_procprio(LMKD_CTRL_PACKET packet, int field_count, struct ucred *cred) {
    //...
    snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", params.pid);
    snprintf(val, sizeof(val), "%d", params.oomadj);//ams传过来的adj值
    if (!writefilestring(path, val, false)) {
        return;
    }

    //...
}
  • oom_adj: oom_score_adj より前の古いインターフェースです。互換性のために残されています。値は -16 ~ 15 です。値が -17 の場合、oom Killer の管理はオフになります。ユーザーがこの値を変更すると、後でカーネル内で oom_score_adj に変換されます。
//kernel/msm-4.19/Documentation/filesystems/proc.txt

For backwards compatibility with previous kernels, /proc/<pid>/oom_adj may also
be used to tune the badness score.  Its acceptable values range from -16
(OOM_ADJUST_MIN) to +15 (OOM_ADJUST_MAX) and a special value of -17
(OOM_DISABLE) to disable oom killing entirely for that task.  Its value is
scaled linearly with /proc/<pid>/oom_score_adj.

Android ローメモリキラー(lmk)

  • Android は主にユーザー空間で lmkd を使用して管理し、主にアプリ指向のメモリ管理プロセス (通常、システム プロセス oom_adj は 0 未満で、lmkd は oom_adj >= 0 のプロセスのみを強制終了します) を使用し、また oom_adj と oom_score_adj を使用して oom_score スコアを計算します。どのプロセスを強制終了するかを決定するには、プロセスの分類とタイミング検出メカニズムを追加するだけです。各レベルには独自のしきい値があり、トリガーされると、レベルに従ってプロセスのバッチが強制終了されます。
  • オムキラーをいつ使用するか? 決して使用しませんでした。
  • linux oom Killer と比較して、lmkd は Android で有効です。linux oom android のコードはカーネルにコンパイルされますが、トリガーされません。最初にトリガーされるのは常に lmkd です (理由はわかりませんが、しきい値が設定されているためでしょうか) lmkd の値は oom Killer の値より低い?)。lmkd はシステム全体のしきい値に基づいて、一定のしきい値を下回ると lmk が起動され、独自の独立したプロセス lmkd を持ちますが、Linux oom はメモリ割り当てが不十分な場合に起動されます。
  • oomメモリガードテーブル

  • このテーブルは対応関係を定義します。各警告値は重要度の値に対応します。システムの利用可能なメモリが特定の警告値よりも低い場合、警告値に対応する重要度の値より大きいプログラムはすべて強制終了されます。たとえば、使用可能なメモリが 6144 * 4K = 24MB 未満の場合は、adj 15 ですべてのプロセスの強制終了を開始し、使用可能なメモリが 5632 * 4K = 22MB 未満の場合は、adj 14 ですべてのプロセスの強制終了を開始します。
  • Android AMS は、アプリのステータスと LRU メカニズムに応じてアプリの oom_score_adj 値を変更するため、lmkd でのアプリのレベルと強制終了の優先順位に影響します。

アンドロイドアプリのオム

マルチタスク環境を維持するために、Android は各アプリケーションのヒープ サイズにハード キャップを設定します。さまざまなデバイスの正確な最大ヒープ サイズは、デバイスの利用可能な全体的な RAM サイズによって異なります。ヒープ容量の制限に達した後、アプリがさらにメモリを割り当てようとすると、このメッセージが表示されることがありますOutOfMemoryError

引用元: https://developer.android.com/topic/performance/memory-overview?hl=zh-cn

クスワップ

Linux と比較すると、従来の kswapd はディスクをスワップ メモリとして使用し、メモリの内容をディスクにスワップします。

android kswapd、メモリ(zRAM)をスワップメモリ​​として使用し、圧縮と解凍を追加します(実際にはこれもLinuxから派生していますが、Androidでのみ使用されます。Linuxには便利なものとそうでないものがあると思います。zSwap、 zCacha など (Linux の人はまだ詳しく知りません)。

メモリが不足している場合、kswapd が最初にトリガーされ、クリーン ページの内容を削除してメモリを解放し、ダーティ ページの内容を圧縮して zRAM に書き込みます。ダーティ ページに関連付けられたプロセスが終了すると、zRAM が解放されます。この後は不十分です。低メモリキラーをトリガーします。

画像から: https://developer.android.com/topic/performance/memory-management?hl=zh-cn#kswapd

zRAM

zRAM ハードウェアもメモリ スティックを使用して、スワップと同様の機能を実装します。これは kswapd によって管理されます。データは、zRAM に出入りするときに圧縮および解凍されます。zRAM スペースは、データ量に応じて、または / を通じて動的に拡張および縮小できます。 sys/block /zram0/disksize を参照して構成します。本質は、時間を空間と交換し、CPU の解凍と圧縮をより多くのメモリ空間と交換することです (具体的な圧縮アルゴリズムはまだ理解されていません)。

zRAM はブロック デバイスの形式です。ドライバー コードは kernel/msm-4.19/drivers/block/zram/z​​ram_drv.c にあります。ブロック デバイスを作成し、IO インターフェイスを提供します。ドライバーは物理ハードウェアの一部を分割します。ブート時に使用するメモリ。ユーザー空間は /sys/block/zram0 を通じて zRAM と対話します。

kswapd と lmkd

メモリが足りない場合は、まず kswapd を起動してメモリ圧縮を実行します。例えば、Qualcomm Snapdragon 888 ではスワップに 4GB が使用されます。4GB がある程度使用された後 (このレベルは固定されていません。理由はまだわかりません)、 8GB Qualcomm Snapdragon 888 携帯電話で試してみました) 回 (4GB が使用される場合もあれば、2GB が使用される場合もあり、1GB が使用される場合もあります)、lmkd がプロセスの強制終了を開始します。

要約する

一般に Android の場合、メモリ不足を管理するサービスは kswapd と lmkd の 2 つがあり、メモリが不足すると、まず kswapd が起動され、クリーン ページのメモリ内容を削除するか、ダーティ ページのメモリ内容を ZRam に圧縮して解放されます。メモリが十分でない場合は、lmkd をトリガーし、oom_score に基づいてどのアプリ プロセスを強制終了するかを決定します。AMS は、アプリのステータスと lru メカニズムに基づいて、lmkd を通じてアプリの oom_score_adj を変更します。これにより、強制終了されるアプリの優先順位に影響します。 lmkd。

参考:

https://blog.csdn.net/jun5753/article/details/105670683

https://jekton.github.io/2019/03/21/android9-lmk-lmkd/

https://blog.csdn.net/johnWcheung/article/details/87600413

https://developer.android.com/topic/performance/memory-management?hl=zh-cn#kswapd

https://kernel.meizu.com/zram-introduction.html

http://www.wowotech.net/memory_management/zram.html

https://developer.android.com/topic/performance/memory-overview?hl=zh-cn

カーネル/msm-4.19/ドキュメント/ファイルシステム/proc.txt

おすすめ

転載: blog.csdn.net/goodnight1994/article/details/118556198