Linuxメモリ管理におけるRSSおよびVSZとは


回答:


499

RSSは常駐セットサイズであり、そのプロセスに割り当てられ、RAMにあるメモリの量を示すために使用されます。スワップアウトされたメモリは含まれません。これらのライブラリのページが実際にメモリ内にある限り、共有ライブラリのメモリも含まれます。すべてのスタックおよびヒープメモリが含まれます。

VSZは仮想メモリサイズです。スワップアウトされたメモリ、割り当てられているが使用されていないメモリ、共有ライブラリからのメモリなど、プロセスがアクセスできるすべてのメモリが含まれます。

したがって、プロセスAに500Kバイナリがあり、2500Kの共有ライブラリにリンクされている場合、200Kのスタック/ヒープ割り当てがあり、そのうち100Kは実際にメモリ内にあり(残りはスワップまたは未使用)、実際にロードされているのは1000Kの共有ライブラリだけです。そして、独自のバイナリの400K:

RSS: 400K + 1000K + 100K = 1500K
VSZ: 500K + 2500K + 200K = 3200K

メモリの一部が共有されているため、多くのプロセスがそれを使用する可能性があるため、RSS値のすべてを合計すると、システムよりも多くのスペースが簡単に生じる可能性があります。

割り当てられたメモリも、プログラムで実際に使用されるまでRSSにない場合があります。したがって、プログラムが大量のメモリを事前に割り当て、その後それを長期にわたって使用する場合、RSSが上昇し、VSZが同じままであることがわかります。

PSS(比例設定サイズ)もあります。これは、現在のプロセスで使用されている比率として共有メモリを追跡する新しい方策です。したがって、以前と同じ共有ライブラリを使用している2つのプロセスがある場合:

PSS: 400K + (1000K/2) + 100K = 400K + 500K + 100K = 1000K

スレッドはすべて同じアドレス空間を共有するため、各スレッドのRSS、VSZ、およびPSSは、プロセス内の他のすべてのスレッドと同一です。この情報をlinux / unixで表示するには、psまたはtopを使用します。

これ以外にも方法があります。詳細については、次のリファレンスを確認してください。

こちらもご覧ください:


17
RSSに動的にリンクされたライブラリのメモリ含まれていると思います。を使用するプロセスが3つある場合libxml2.so、共有ライブラリはそれぞれのRSSでカウントされるため、RSSの合計は実際に使用されているメモリよりも多くなります。
nfm 2014

1
それは正しいです。頭を上げてくれてありがとう。
jmh 2014

私はubuntu 16.04を使っていて、topコマンドから1.2G RESと4.5G VIRTを表示するJavaプロセスがあります。このシステムにはスワップswapon --showがなく、何も返しません。これをどう説明しますか?vszがswap +共有ライブラリの場合、この場合、共有ライブラリは3.3Gを超えていますか?出来ますか?本当に混乱しています...
アーロンワン

よくわかりません。Java仮想メモリの使用に関するこの回答を見てください:stackoverflow.com/a/561450/622115。ショートバージョン:VSZには、割り当てられて使用されていないヒープスペースと、メモリマップファイルを含めることができます。
jmh 2017年

すごい。何かを追加するだけです。malloc(100KB)の場合、実際には1KBしか使用しません。ここにスワップがない場合でも、rssは1K、vszは100Kです。
ケニーバン2018

53

RSSは常駐セットサイズ(物理的に常駐のメモリ-これは現在、マシンの物理メモリ内のスペースを占有しています)、VSZは仮想メモリサイズ(割り当てられたアドレススペース-これは、プロセスのメモリマップにアドレスが割り当てられていますが、必ずしも必要ではありません)現在、その背後にある実際のメモリ)。

最近のありふれた仮想マシンでは、マシンから見た物理メモリは実際の物理メモリではない場合があることに注意してください。


略語が表すものよりも多くの情報を提供することに心がけていますか?
ピティコス2016年

10

最小限の実行可能な例

これを理解するには、ページングの基本を理解する必要があります。x86ページングは​​どのように機能しますか?特に、OSが実際にRAMまたはディスク(RSS常駐メモリ)にバッキングストレージを配置する前に、ページテーブル/内部メモリブックキーピング(VSZ仮想メモリ)を介して仮想メモリを割り当てることができること。

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

  • 物理メモリより多くのRAMを割り当てます mmap
  • 各ページに1バイトを書き込んで、それらの各ページが仮想オンリーメモリ(VSZ)から実際に使用されたメモリ(RSS)に移動するようにします。
  • プロセスのメモリ使用量を次のいずれかの方法でチェックします: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;

/* /programming/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:
         * /programming/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の2Gの32GiB
  • 0x200000000 == 8GiB:8GiBごとにメモリを印刷するため、約32GiBでクラッシュする前に4枚の印刷を取得する必要があります
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory:Linuxがmmap呼び出しを物理RAMよりも大きくできるようにするために必要:mallocが割り当てることができる最大メモリ

プログラム出力:

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の+シグナル番号規則の手段我々は、信号の数だ9man 7 signalと言うSIGKILL Linuxが送信され、アウト・オブ・メモリキラーを

出力の解釈:

  • VSZ仮想メモリはmmap後もprintf '0x%X\n' 0x40009A4 KiB ~= 64GiBps値はKiBで)一定です。
  • RSSの「実際のメモリ使用量」は、ページに触れるだけでゆっくりと増加します。例えば:
    • 最初のプリントにはがありextra_memory_committed 0、これはまだどのページにも触れていないことを意味します。RSSは小さな1648 KiBもので、テキスト領域やグローバルなどの通常のプログラムの起動用に割り当てられています。
    • 2枚目の印刷では、8388608 KiB == 8GiB相当数のページに書き込みました。その結果、RSSは8GIBだけ増加し、8390256 KiB == 8388608 KiB + 1648 KiB
    • RSSは、8GiBの増分で増加し続けています。最後の印刷は約24 GiBのメモリを示し、32 GiBが印刷される前に、OOMキラーはプロセスを強制終了しました

参照:https : //unix.stackexchange.com/questions/35129/need-explanation-on-resident-set-size-virtual-size

OOMキラーログ

私たちのdmesgコマンドは、OOMキラーログを示しています。

それらの正確な解釈は以下で尋ねられました:

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

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

興味深いことに、おそらくバックグラウンドで私のラップトップで常に実行されているのは、MongoDBデーモンであり、おそらくOOMキラーが最初にトリガーされました。

ただし、OOMキラーは、目覚めた人を殺すとは限りません。

呼び出し後、カーネルはテーブルまたはプロセスを出力しますoom_score

[ 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

さらに先main.outに、以前の呼び出しで実際に自分の小さなものが殺されたことがわかります。

[ 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

このログは、score 865そのプロセスが持っていたものについて言及しています。最初に殺すプロセス

また、興味深いことに、すべてが非常に速く発生したため、解放されたメモリが使用される前にoomDeadlineMonitorプロセスによって再び起こされました。

[ 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でテスト済み。


8

RSSとVSZについては、すでに多くのことが語られていると思います。管理者/プログラマー/ユーザーの観点から、アプリケーションを設計/コード化するときは、RSZ(常駐メモリ)にさらに関心があります。また、ますます多くの変数(ヒープ)を取得し続けると、この値が急上昇するのがわかります。簡単なプログラムを試して、mallocベースのスペース割り当てをループで構築し、そのmallocで割り当てられたスペースにデータを入力してください。RSSは上昇を続けています。VSZに関する限り、それはlinuxが行う仮想メモリマッピングであり、従来のオペレーティングシステムの概念から派生したコア機能の1つです。VSZの管理はカーネルの仮想メモリ管理によって行われます。VSZの詳細については、カーネルの基本的なtask_structデータ構造の一部であるmm_structおよびvm_structに関するRobert Loveの説明を参照してください。


Loveの本「Linux Kernel Development」を参照していますか?
ベンジミン

1

それらは管理されていませんが、測定され、おそらく制限されています(getrlimit(2)のgetrlimitシステムコールを参照)。

RSSは、常駐セットサイズ(RAMにある仮想アドレス空間の一部)を意味します。

proc(5)とそのステータス(メモリ消費を含むを使用して、プロセス1234の仮想アドレス空間を照会できます。cat /proc/1234/mapscat /proc/1234/status


1
このリンクで質問に答えることができますが、回答の重要な部分をここに含め、参照用のリンクを提供することをお勧めします。リンクされたページが変更されると、リンクのみの回答が無効になる可能性があります。- 口コミより
Maak

2つ目のリンクを提供しました。そのうちの1つは有効なままです
Basile Starynkevitch 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.