Объяснение потребности на Размере Размера Резидентного набора / Виртуальном Размере

Давайте улучшим ответ P.T.:s просто немного.

Каноническая форма отправляет весь нормальный вывод в файл журнала.

./run_all_with_logs >> logs/my.log &

Если мы перенаправляем ошибки, мы можем зарегистрировать и ошибки и нормальные распечатки.

./run_all_with_logs 2>&1 >> logs/my.log &

Если мы затем выполняем команду в подоболочке, мы можем распечатать код выхода также.

(./run_all_with_logs ; echo "Final Exit Code: $?" ) 2>&1  >> logs/my.log &
62
18.02.2017, 20:41
2 ответа

RSS - то, сколько памяти этот процесс в настоящее время имеет в оперативной памяти (RAM). VSZ - то, сколько виртуальной памяти процесс имеет всего. Это включает все типы памяти, и в RAM и выгруженный. Эти числа могут быть скошены, потому что они также включают совместно использованные библиотеки и другие типы памяти. У Вас может быть пятьсот экземпляров bash выполнение, и общий размер их объема потребляемой памяти не будет суммой их RSS или значений VSZ.

Если необходимо получить более подробную идею об объеме потребляемой памяти процесса, у Вас есть некоторые опции. Можно пройти /proc/$PID/map и избавьтесь от материала, который Вы не любите. Если это совместно использовало библиотеки, вычисление могло бы стать сложным в зависимости от Ваших потребностей (который я думаю, что помню).

Если Вы только заботитесь о размере "кучи" процесса, можно всегда просто анализировать [heap] запись в map файл. Размер, который ядро выделило для "кучи" процесса, может или не может отразить точное число байтов, процесс попросил быть выделенным. Существуют мелкие подробности, внутренности ядра и оптимизации, которые могут отбросить это. В идеальном мире это будет так же, как для Вашего процесса нужно, окруженный к ближайшему несколько из системного размера страницы (getconf PAGESIZE скажет Вам, что это — на ПК, это - вероятно, 4 096 байтов).

Если Вы хотите видеть, сколько памяти процесс выделил, один из лучших путей состоит в том, чтобы воздержаться от метрик стороны ядра. Вместо этого Вы оснащаете память "кучи" библиотеки C (de) функции выделения с LD_PRELOAD механизм. Лично, я немного злоупотребляю valgrind получить информацию об этом виде вещи. (Обратите внимание, что применение инструментария потребует перезапуска процесса.)

Отметьте, так как можно также сравнивать времени выполнения, этого valgrind сделает Ваши программы очень немного медленнее (но вероятно в рамках Ваших допусков).

64
27.01.2020, 19:32
  • 1
    Большое спасибо! Я собираюсь исследовать различные варианты. Вы были более, чем услужливы! :) –  Flanfl 27.03.2012, 21:17
  • 2
    "У Вас может быть пятьсот экземпляров выполнения удара, и общий размер их объема потребляемой памяти не будет суммой их RSS или значений VSZ". Но будет сумма их значений RSS быть хорошим приближением? Как сумма резидентного столбца от statm, мне не нужно супер надежное точное значение, но я должен знать высокий уровень, сколько памяти мои процессы Java используют –  hahahahahahahaha 28.07.2017, 18:23
  • 3
    На Ubuntu это /proc/$PID/maps вот в чем разница в дистрибутиве или опечатка? –  dolzenko 15.02.2018, 13:11

Минимальный запускаемый пример

Чтобы это имело смысл, вы должны понимать основы пейджинга:https://stackoverflow.com/questions/18431261/how-does-x86-paging-workи, в частности, то, что ОС может выделять виртуальную память через таблицы страниц / свой внутренний бухгалтерский учет памяти (Виртуальная память VSZ )перед этим. фактически имеет резервное хранилище в ОЗУ или на диске (Резидентная память RSS ).

Теперь, чтобы увидеть это в действии, давайте создадим программу, которая:

  • выделяет больше оперативной памяти, чем наша физическая память сmmap
  • записывает один байт на каждую страницу, чтобы каждая из этих страниц перемещалась из виртуальной памяти (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 :2x физическая оперативная память моего компьютера 32GiB
  • 0x200000000 == 8GiB :печатать память через каждые 8GiB, поэтому мы должны получить 4 отпечатка до сбоя около 32GiB
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory:требуется для Linux, чтобы позволить нам сделать вызов 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 + номер сигнала означает, что мы получили номер сигнала 9, который man 7 signalговорит, что это SIGKILL , который отправляется Linux out -из -убийцы памяти .

Интерпретация выхода:

  • Виртуальная память VSZ остается неизменной:printf '0x%X\n' 0x40009A4 KiB ~= 64GiB(psзначения указаны в КиБ )после mmap.
  • RSS "реальное использование памяти" увеличивается лениво, только когда мы касаемся страниц. Например :
    • на первом отпечатке у нас есть extra_memory_committed 0, что означает, что мы еще не коснулись ни одной страницы.RSS — это небольшой 1648 KiB, который был выделен для нормального запуска программы, такой как текстовая область, глобальные переменные и т. д.
    • на втором оттиске мы написали на 8388608 KiB == 8GiBстраниц. В результате RSS увеличился ровно на 8GB до8390256 KiB == 8388608 KiB + 1648 KiB
    • RSS продолжает увеличиваться с шагом 8 ГБ. Последний отпечаток показывает около 24 ГиБ памяти, и до того, как удалось распечатать 32 ГиБ, убийца OOM убил процесс
    • .

См. также:Необходимо пояснение по размеру резидентного набора/виртуальному размеру

Журналы убийц OOM

Наши команды dmesgпоказали журналы убийц OOM.

Точная интерпретация их была запрошена на:

Самая первая строка журнала была:

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

Итак, мы видим, что интересно, что именно демон MongoDB, который всегда работает в моем ноутбуке в фоновом режиме, первым вызвал убийцу 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, который имел этот процесс, предположительно самый высокий (худший )показатель убийцы OOM, как указано в:Как убийца OOM решает, какой процесс убить первым?

Также интересно, что все видимо произошло так быстро, что до того, как освободившаяся память была засчитана, oomснова разбудил DeadlineMonitorпроцесс:

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

11
20.08.2021, 13:27

Теги

Похожие вопросы