Perlu penjelasan tentang Resident Set Size / Ukuran Virtual


61

Saya menemukan itu pidstatakan menjadi alat yang baik untuk memantau proses. Saya ingin menghitung penggunaan memori rata-rata dari proses tertentu. Berikut adalah beberapa contoh output:

02:34:36 PM       PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
02:34:37 PM      7276      2.00      0.00  349212 210176   7.14  scalpel

(Ini adalah bagian dari output dari pidstat -r -p 7276.)

Haruskah saya menggunakan informasi Resident Set Size (RSS) atau Virtual Size (VSZ) untuk menghitung konsumsi memori rata-rata? Saya telah membaca beberapa hal di Wikipedia dan di forum, tetapi saya tidak yakin untuk sepenuhnya memahami perbedaannya. Plus, tampaknya tidak satupun dari mereka yang dapat diandalkan. Jadi, bagaimana saya bisa memonitor suatu proses untuk mendapatkan penggunaan memorinya?

Bantuan apa pun tentang hal ini akan bermanfaat.



Jawaban:


63

RSS adalah berapa banyak memori yang dimiliki proses ini saat ini dalam memori utama (RAM). VSZ adalah jumlah total memori virtual yang dimiliki proses. Ini termasuk semua jenis memori, baik dalam RAM dan bertukar. Angka-angka ini dapat miring karena mereka juga termasuk perpustakaan bersama dan jenis memori lainnya. Anda dapat memiliki lima ratus contoh bashberjalan, dan ukuran total jejak memori mereka tidak akan menjadi jumlah nilai RSS atau VSZ mereka.

Jika Anda perlu mendapatkan ide yang lebih rinci tentang jejak memori suatu proses, Anda memiliki beberapa opsi. Anda dapat melewati /proc/$PID/mapdan menyingkirkan hal-hal yang tidak Anda sukai. Jika itu adalah pustaka bersama, perhitungannya bisa menjadi rumit tergantung pada kebutuhan Anda (yang saya pikir saya ingat).

Jika Anda hanya peduli tentang ukuran tumpukan proses, Anda selalu bisa menguraikan [heap]entri dalam mapfile. Ukuran kernel yang dialokasikan untuk tumpukan proses mungkin atau mungkin tidak mencerminkan jumlah byte yang tepat yang diminta dialokasikan oleh proses. Ada detail kecil, kernel internal dan optimisasi yang dapat membuang ini. Di dunia yang ideal, ini akan sebanyak yang dibutuhkan proses Anda, dibulatkan ke kelipatan terdekat dari ukuran halaman sistem ( getconf PAGESIZEakan memberi tahu Anda apa itu - pada PC, mungkin 4.096 byte).

Jika Anda ingin melihat berapa banyak memori yang telah dialokasikan oleh suatu proses , salah satu cara terbaik adalah melepaskan metrik sisi kernel. Sebagai gantinya, Anda instrumen fungsi tumpukan memori (de) alokasi perpustakaan C dengan LD_PRELOADmekanisme. Secara pribadi, saya sedikit menyalahgunakan valgrinduntuk mendapatkan informasi tentang hal semacam ini. (Perhatikan bahwa menerapkan instrumentasi akan membutuhkan memulai kembali proses.)

Harap dicatat, karena Anda mungkin juga menjadi benchmark runtimes, yang valgrindakan membuat program Anda sedikit lebih lambat (tapi mungkin dalam toleransi Anda).


Terima kasih banyak! Saya akan menyelidiki opsi yang berbeda. Anda lebih dari membantu! :)
Flanfl

"Anda dapat memiliki lima ratus contoh menjalankan bash, dan ukuran total jejak memori mereka tidak akan menjadi jumlah nilai RSS atau VSZ mereka." Tetapi apakah jumlah nilai RSS mereka akan menjadi perkiraan yang baik? Seperti jumlah kolom penduduk dari statm, saya tidak memerlukan nilai tepat yang dapat diandalkan, tetapi saya perlu tahu tingkat tinggi berapa banyak memori yang digunakan proses java saya
iloveretards

3
Di Ubuntu /proc/$PID/mapsapakah itu perbedaan ketik atau distro?
dolzenko

1

Contoh runnable minimal

Agar ini masuk akal, Anda harus memahami dasar-dasar paging: https://stackoverflow.com/questions/18431261/how-does-x86-paging-work dan khususnya bahwa OS dapat mengalokasikan memori virtual melalui tabel halaman / penyimpanan buku memori internal (memori virtual VSZ) sebelum benar-benar memiliki penyimpanan dukungan pada RAM atau disk (memori residen RSS).

Sekarang untuk mengamati ini dalam tindakan, mari kita buat program yang:

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 hulu .

Kompilasi dan jalankan:

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

dimana:

Output program:

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

Status keluar:

137

yang dengan aturan nomor sinyal 128+ berarti kami mendapat nomor sinyal 9, yang man 7 signalmengatakan adalah SIGKILL , yang dikirim oleh Linux out-of-memory killer .

Interpretasi keluaran:

  • Memori virtual VSZ tetap konstan pada printf '0x%X\n' 0x40009A4 KiB ~= 64GiB( psnilai-nilai dalam KiB) setelah mmap.
  • RSS "penggunaan memori nyata" hanya meningkat malas saat kita menyentuh halaman. Sebagai contoh:
    • pada cetakan pertama, kita miliki extra_memory_committed 0, yang berarti kita belum menyentuh halaman mana pun. RSS adalah kecil 1648 KiByang telah dialokasikan untuk startup program normal seperti area teks, global, dll.
    • pada cetakan kedua, kami telah menulis hingga 8388608 KiB == 8GiBsenilai halaman. Akibatnya, RSS meningkat hingga 8GIB menjadi8390256 KiB == 8388608 KiB + 1648 KiB
    • RSS terus meningkat dengan peningkatan 8GiB. Cetakan terakhir menunjukkan sekitar 24 GiB memori, dan sebelum 32 GiB dapat dicetak, pembunuh OOM membunuh prosesnya

Lihat juga: Perlu penjelasan tentang Resident Set Size / Ukuran Virtual

Log pembunuh OOM

dmesgPerintah kami telah menunjukkan log pembunuh OOM.

Penafsiran yang tepat dari mereka telah ditanyakan di:

Baris pertama dari log adalah:

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

Jadi kita melihat bahwa yang menarik adalah daemon MongoDB yang selalu berjalan di laptop saya di latar belakang yang pertama kali memicu pembunuh OOM, mungkin ketika hal yang buruk itu mencoba mengalokasikan beberapa memori.

Namun, pembunuh OOM tidak harus membunuh orang yang membangunkannya.

Setelah doa, kernel mencetak tabel atau proses termasuk 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

dan lebih jauh ke depan kita melihat bahwa anak kita sendiri main.outbenar - benar terbunuh pada doa sebelumnya:

[ 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

Log ini menyebutkan proses score 865mana yang memiliki, mungkin skor pembunuh OOM tertinggi (terburuk) sebagaimana disebutkan di: Bagaimana pembunuh OOM memutuskan proses pembunuhan mana yang lebih dulu?

Yang menarik, segala sesuatu tampaknya terjadi begitu cepat sehingga sebelum ingatan yang bebas dicatat, oomdibangunkan kembali oleh DeadlineMonitorproses:

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

dan kali ini yang membunuh beberapa proses Chromium, yang biasanya komputer saya memori normal babi:

[ 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

Diuji di Ubuntu 19.04, kernel Linux 5.0.0.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.