Что такое RSS и VSZ в управлении памятью Linux? В многопоточной среде, как можно управлять и отслеживать оба из них?
Что такое RSS и VSZ в управлении памятью Linux
Ответ 1
RSS - это размер резидентного набора, который используется, чтобы показать, сколько памяти выделено этому процессу и находится в оперативной памяти. Он не включает память, которая выгружается. Он включает в себя память из общих библиотек, пока страницы из этих библиотек фактически находятся в памяти. Он включает в себя всю память стека и кучи.
VSZ - это размер виртуальной памяти. Он включает в себя всю память, к которой может обращаться процесс, включая память, которая выгружается, память, которая выделена, но не используется, и память из общих библиотек.
Таким образом, если процесс A имеет двоичный файл размером 500 КБ и связан с 2500 КБ совместно используемых библиотек, имеет 200 КБ выделенных стеков/кучи, из которых 100 КБ фактически находятся в памяти (остальная часть поменялась местами или не используется), и он фактически загрузил только 1000 КБ совместно используемых библиотек. и 400K своего двоичного файла:
RSS: 400K + 1000K + 100K = 1500K
VSZ: 500K + 2500K + 200K = 3200K
Поскольку часть памяти является общей, многие процессы могут использовать ее, поэтому, если вы сложите все значения RSS, у вас может легко оказаться больше места, чем в вашей системе.
Память, которая выделяется, также может отсутствовать в RSS, пока она не будет фактически использована программой. Таким образом, если ваша программа выделяет кучу памяти заранее, а затем использует ее со временем, вы можете увидеть, что RSS растет, а VSZ остается прежним.
Существует также PSS (пропорциональный размер набора). Это более новая мера, которая отслеживает общую память как пропорцию, используемую текущим процессом. Итак, если раньше было два процесса, использующих одну и ту же общую библиотеку:
PSS: 400K + (1000K/2) + 100K = 400K + 500K + 100K = 1000K
Все потоки имеют одинаковое адресное пространство, поэтому RSS, VSZ и PSS для каждого потока идентичны всем другим потокам в процессе. Используйте ps или top для просмотра этой информации в linux/unix.
Это намного больше, чем это, чтобы узнать больше, проверьте следующие ссылки:
- http://manpages.ubuntu.com/manpages/en/man1/ps.1.html
- https://web.archive.org/web/20120520221529/http://emilics.com/blog/article/mconsumption.html
Также смотрите:
Ответ 2
RSS - это размер резидентного набора (физически резидентная память - это в настоящее время занимает пространство в физической памяти аппарата), а VSZ - размер виртуальной памяти (выделено адресное пространство - это адреса, выделенные на карте памяти процесса, t обязательно любая фактическая память за всем этим прямо сейчас).
Обратите внимание, что в эти дни обычных виртуальных машин физическая память с точки зрения компьютера может быть не реальной физической памятью.
Ответ 3
Я думаю, много уже сказано, о RSS против VSZ. С точки зрения администратора/программиста/пользователя, когда я разрабатываю/кодирует приложения, меня больше беспокоит RSZ (память резидента), так как когда вы продолжаете тянуть все больше и больше переменных (нагроможденных), вы увидите это значение, стреляющее вверх. Попробуйте простую программу для построения распределения пространства на основе malloc в цикле и убедитесь, что вы заполняете данные в этом пространстве malloc'd. RSS продолжает двигаться вверх. Что касается VSZ, то это скорее виртуальное отображение памяти, которое делает linux, и одна из его основных функций, полученных из обычных концепций операционной системы. Управление VSZ выполняется с помощью управления виртуальной памятью ядра, для получения дополнительной информации о VSZ см. Описание Роберта Лава на mm_struct и vm_struct, которые являются частью основной структуры данных task_struct в ядре.
Ответ 4
Пример минимального запуска
Чтобы это имело смысл, вы должны понимать основы пейджинга: Как работает пейджинг на x86? и, в частности, чтобы ОС могла распределять виртуальную память через таблицы страниц/ведение внутренней памяти (виртуальная память VSZ) ) до того, как на самом деле будет резервное хранилище в ОЗУ или на диске (резидентная память RSS).
Теперь, чтобы увидеть это в действии, давайте создадим программу, которая:
mmap
выделяет больше оперативной памяти, чем наша физическая память- записывает один байт на каждую страницу, чтобы каждая из этих страниц шла из виртуальной памяти RSS и VSZ
- проверяет использование памяти процессом одним из методов, упомянутых в: Использование памяти текущего процесса в 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;
/* /questions/316667/memory-usage-of-current-process-in-c7212248#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:
* /questions/316667/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;
}
Скомпилируйте и запустите:
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 == 64 ГБ: 2x физической памяти моего компьютера 32 ГБ
- 0x200000000 == 8 ГБ: печатать память каждые 8 ГБ, поэтому мы должны получить 4 отпечатка до сбоя около 32 ГБ
echo 1 | sudo tee /proc/sys/vm/overcommit_memory
: требуется для Linux, чтобы мы могли делать вызовы mmap больше физической ОЗУ: максимальный объем памяти, который может выделить 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 + номер сигнала означает, что мы получили номер сигнала 9
, который man 7 signal
говорит, что это SIGKILL, который отправляется Linux из убийцы памяти.
Выходная интерпретация:
- Виртуальная память VSZ остается неизменной на уровне
printf '0x%X\n' 0x40009A4 KiB ~= 64GiB
(значенияps
указаны в КиБ) после mmap. - RSS "реальное использование памяти" увеличивается лениво только при касании страниц. Например:
- на первом отпечатке у нас есть
extra_memory_committed 0
, что означает, что мы еще не коснулись ни одной страницы. RSS - это маленький1648 KiB
, который был выделен для обычного запуска программы, такого как текстовая область, глобальные переменные и т.д. - на втором отпечатке мы написали на
8388608 KiB == 8GiB
количество страниц. В результате RSS увеличился ровно на 8GIB до8390256 KiB == 8388608 KiB + 1648 KiB
- RSS продолжает расти с шагом 8 ГБ. Последний отпечаток показывает около 24 ГиБ памяти, и до того, как 32 ГБ могли быть напечатаны, убийца OOM убил процесс
- на первом отпечатке у нас есть
Смотрите также: https://unix.stackexchange.com/questions/35129/need-explanation-on-resident-set-size-virtual-size
Журналы убийцы OOM
Наши команды dmesg
показали журналы убийцы OOM.
Точная интерпретация этих вопросов была задана по адресу:
- Понимание логов Linux oom-killer, но давайте кратко рассмотрим здесь.
- 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_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, как упомянуто в: https://unix.stackexchange.com/questions/153585/how-does-the-oom-killer-decide-which-process-to-kill-first
Также интересно то, что все, по-видимому, произошло так быстро, что до учета освобожденной памяти процесс 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.
Ответ 5
Они не управляются, но измеряются и, возможно, ограничены (см. getrlimit
системный вызов, также в getrlimit (2)).
RSS означает размер резидентного набора (часть вашего виртуального адресного пространства, расположенная в оперативной памяти).
Вы можете запросить виртуальное адресное пространство процесса 1234 с помощью proc (5) с cat /proc/1234/maps
и его состоянием (включая потребление памяти) через cat /proc/1234/status