GNU/Linux >> Linux の 問題 >  >> Linux

常駐セットサイズ/仮想サイズについて説明が必要

RSS は、このプロセスが現在メイン メモリ (RAM) に持っているメモリの量です。 VSZ は、プロセスが合計で持つ仮想メモリの量です。これには、RAM とスワップアウトの両方のすべてのタイプのメモリが含まれます。これらの数値には、共有ライブラリやその他の種類のメモリも含まれるため、偏りが生じる可能性があります。 02 のインスタンスを 500 個持つことができます

プロセスのメモリ フットプリントについてより詳細に把握する必要がある場合は、いくつかのオプションがあります。 19 を通過できます そして気に入らないものを捨てる。共有ライブラリの場合、必要に応じて計算が複雑になる可能性があります (覚えていると思います)。

プロセスのヒープサイズのみを気にする場合は、いつでも 25 を解析できます 39 のエントリ ファイル。カーネルがプロセス ヒープに割り当てたサイズは、プロセスが要求した正確なバイト数を反映している場合と反映していない場合があります。 割り当てられます。これを無効にする可能性のある詳細、カーネルの内部、および最適化があります。理想的な世界では、システム ページ サイズ (41) の最も近い倍数に切り上げて、プロセスが必要とするだけの量になります。 それが何であるかを教えてくれます — PC では、おそらく 4,096 バイトです)。

プロセスが割り当てたメモリの量を確認したい場合 、最良の方法の 1 つは、カーネル側のメトリックを無視することです。代わりに、C ライブラリのヒープ メモリ (割り当て解除) 関数を 54 で計測します。 機構。個人的には 60 を少し乱用しています この種の情報を得るために。 (インストルメンテーションを適用するには、プロセスを再起動する必要があることに注意してください。)

ランタイムのベンチマークも行っている可能性があるため、74 に注意してください。 プログラムがわずかに遅くなります (ただし、許容範囲内である可能性があります)。


最小限の実行可能な例

これを理解するには、ページングの基本を理解する必要があります。実際に RAM またはディスク上のバッキング ストレージ (RSS 常駐メモリ) を持つ前に、その内部メモリ ブック キーピング (VSZ 仮想メモリ) を保持します。

これを実際に観察するために、次のようなプログラムを作成しましょう:

  • 81 で物理メモリよりも多くの RAM を割り当てます
  • 各ページに 1 バイトを書き込み、各ページが仮想専用メモリ (VSZ) から実際に使用されるメモリ (RSS) に移動するようにします
  • https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c に記載されているいずれかの方法で、プロセスのメモリ使用量をチェックします

main.c

#define _GNU_SOURCE
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

typedef struct {
    unsigned long size,resident,share,text,lib,data,dt;
} ProcStatm;

/* https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c/7212248#7212248 */
void ProcStat_init(ProcStatm *result) {
    const char* statm_path = "/proc/self/statm";
    FILE *f = fopen(statm_path, "r");
    if(!f) {
        perror(statm_path);
        abort();
    }
    if(7 != fscanf(
        f,
        "%lu %lu %lu %lu %lu %lu %lu",
        &(result->size),
        &(result->resident),
        &(result->share),
        &(result->text),
        &(result->lib),
        &(result->data),
        &(result->dt)
    )) {
        perror(statm_path);
        abort();
    }
    fclose(f);
}

int main(int argc, char **argv) {
    ProcStatm proc_statm;
    char *base, *p;
    char system_cmd[1024];
    long page_size;
    size_t i, nbytes, print_interval, bytes_since_last_print;
    int snprintf_return;

    /* Decide how many ints to allocate. */
    if (argc < 2) {
        nbytes = 0x10000;
    } else {
        nbytes = strtoull(argv[1], NULL, 0);
    }
    if (argc < 3) {
        print_interval = 0x1000;
    } else {
        print_interval = strtoull(argv[2], NULL, 0);
    }
    page_size = sysconf(_SC_PAGESIZE);

    /* Allocate the memory. */
    base = mmap(
        NULL,
        nbytes,
        PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS,
        -1,
        0
    );
    if (base == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    /* Write to all the allocated pages. */
    i = 0;
    p = base;
    bytes_since_last_print = 0;
    /* Produce the ps command that lists only our VSZ and RSS. */
    snprintf_return = snprintf(
        system_cmd,
        sizeof(system_cmd),
        "ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == \"%ju\") print}'",
        (uintmax_t)getpid()
    );
    assert(snprintf_return >= 0);
    assert((size_t)snprintf_return < sizeof(system_cmd));
    bytes_since_last_print = print_interval;
    do {
        /* Modify a byte in the page. */
        *p = i;
        p += page_size;
        bytes_since_last_print += page_size;
        /* Print process memory usage every print_interval bytes.
         * We count memory using a few techniques from:
         * https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c */
        if (bytes_since_last_print > print_interval) {
            bytes_since_last_print -= print_interval;
            printf("extra_memory_committed %lu KiB\n", (i * page_size) / 1024);
            ProcStat_init(&proc_statm);
            /* Check /proc/self/statm */
            printf(
                "/proc/self/statm size resident %lu %lu KiB\n",
                (proc_statm.size * page_size) / 1024,
                (proc_statm.resident * page_size) / 1024
            );
            /* Check ps. */
            puts(system_cmd);
            system(system_cmd);
            puts("");
        }
        i++;
    } while (p < base + nbytes);

    /* Cleanup. */
    munmap(base, nbytes);
    return EXIT_SUCCESS;
}

GitHub アップストリーム。

コンパイルして実行:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
echo 1 | sudo tee /proc/sys/vm/overcommit_memory
sudo dmesg -c
./main.out 0x1000000000 0x200000000
echo $?
sudo dmesg

ここで:

  • 0x1000000000 ==64GiB:コンピューターの物理 RAM 32GiB の 2 倍
  • 0x200000000 ==8GiB:8GiB ごとにメモリを出力するため、約 32GiB でクラッシュする前に 4 つの出力を取得する必要があります
  • 92 :Linux が物理 RAM よりも大きな mmap 呼び出しを行えるようにするために必要です:https://stackoverflow.com/questions/2798330/maximum-memory-which-malloc-can-allocate/57687432#57687432

プログラム出力:

extra_memory_committed 0 KiB
/proc/self/statm size resident 67111332 768 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 1648

extra_memory_committed 8388608 KiB
/proc/self/statm size resident 67111332 8390244 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 8390256

extra_memory_committed 16777216 KiB
/proc/self/statm size resident 67111332 16778852 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 16778864

extra_memory_committed 25165824 KiB
/proc/self/statm size resident 67111332 25167460 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 25167472

Killed

終了ステータス:

137

これは、128 + シグナル番号の規則により、シグナル番号 107 を取得したことを意味します 、これ 115 Linux のメモリ不足キラーによって送信される SIGKILL です。

出力解釈:

  • VSZ 仮想メモリは 124 で一定です (133 mmap の後の値は KiB 単位です。
  • RSS の「実際のメモリ使用量」は、ページにアクセスするたびにゆっくりと増加します。例:
    • 最初のプリントでは 146 です 、つまり、まだどのページにも触れていません。 RSS は小さな 156 です これは、テキスト領域、グローバルなどの通常のプログラムの起動に割り当てられています。
    • 2 回目の印刷では、160 に書き込みました。 ページの価値。その結果、RSS は正確に 8GIB 増加して 174 になりました
    • RSS は 8GiB 単位で増加し続けています。最後の出力は約 24 GiB のメモリを示しており、32 GiB が出力される前に、OOM キラーがプロセスを強制終了しました

関連項目:常駐セット サイズ/仮想サイズについての説明が必要

OOM キラー ログ

私たちの 189 コマンドは OOM キラー ログを表示しました。

これらの正確な解釈については、

で尋ねられています。
  • https://stackoverflow.com/questions/9199731/understanding-the-linux-oom-killers-logs ですが、ここで簡単に見てみましょう。
  • https://serverfault.com/questions/548736/how-to-read-oom-killer-syslog-messages

ログの最初の行は次のとおりです:

[ 7283.479087] mongod invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

興味深いことに、私のラップトップで常にバックグラウンドで実行されている MongoDB デーモンが、最初に OOM キラーをトリガーしたことがわかります。おそらく、メモリを割り当てようとしていたときに発生しました。

ただし、OOM キラーは、それを起こした人を必ずしも殺すとは限りません。

呼び出しの後、カーネルは 190 を含むテーブルまたはプロセスを出力します :

[ 7283.479292] [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
[ 7283.479303] [    496]     0   496    16126        6   172032      484             0 systemd-journal
[ 7283.479306] [    505]     0   505     1309        0    45056       52             0 blkmapd
[ 7283.479309] [    513]     0   513    19757        0    57344       55             0 lvmetad
[ 7283.479312] [    516]     0   516     4681        1    61440      444         -1000 systemd-udevd

さらに先に、私たち自身の小さな 200 が表示されます 前回の呼び出しで実際に殺されました:

[ 7283.479871] Out of memory: Kill process 15665 (main.out) score 865 or sacrifice child
[ 7283.479879] Killed process 15665 (main.out) total-vm:67111332kB, anon-rss:92kB, file-rss:4kB, shmem-rss:30080832kB
[ 7283.479951] oom_reaper: reaped process 15665 (main.out), now anon-rss:0kB, file-rss:0kB, shmem-rss:30080832kB

このログは 212 について言及しています そのプロセスが持っていた、おそらく最高 (最悪) の OOM キラー スコア:OOM キラーは最初にどのプロセスを強制終了するかをどのように決定しますか?

また興味深いことに、解放されたメモリが考慮される前に、すべてが非常に速く起こったようです。 235 によって再び起こされました プロセス:

[ 7283.481043] DeadlineMonitor invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

今回は Chromium プロセスを強制終了しました。これは通常、私のコンピューターの通常のメモリ ホグです:

[ 7283.481773] Out of memory: Kill process 11786 (chromium-browse) score 306 or sacrifice child
[ 7283.481833] Killed process 11786 (chromium-browse) total-vm:1813576kB, anon-rss:208804kB, file-rss:0kB, shmem-rss:8380kB
[ 7283.497847] oom_reaper: reaped process 11786 (chromium-browse), now anon-rss:0kB, file-rss:0kB, shmem-rss:8044kB

Ubuntu 19.04、Linux カーネル 5.0.0 でテスト済み。


Linux
  1. C での現在のプロセスのメモリ使用量

  2. malloc はメモリまたは仮想アドレス空間を返します

  3. 仮想アドレス空間でページサイズはどのように決定されますか?

  1. LinuxコマンドラインでRAMサイズをGbで確認する方法

  2. Linuxコマンド:vmstatを使用した仮想メモリの探索

  3. Zathuraフルスクリーンを開始/ウィンドウサイズを覚えていますか?

  1. QEMU-KVM上のWindows10VMの仮想ディスクサイズを増やします

  2. Linux –常駐セットサイズ/仮想サイズについての説明が必要ですか?

  3. Apacheでファイルのアップロードサイズの制限を設定するにはどうすればよいですか?