Fla*_*nfl 71 linux process memory
我发现这pidstat将是监控流程的好工具。我想计算特定进程的平均内存使用量。这是一些示例输出:
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
Run Code Online (Sandbox Code Playgroud)
(这是输出的一部分pidstat -r -p 7276。)
我应该使用常驻集大小 (RSS) 或虚拟大小 (VSZ) 信息来计算平均内存消耗吗?我在维基百科和论坛上阅读了一些内容,但我不确定是否完全理解这些差异。另外,似乎它们都不可靠。那么,如何监视进程以获取其内存使用情况?
对此事的任何帮助都会有所帮助。
Ale*_*ios 75
RSS 是此进程当前在主内存 (RAM) 中的内存量。VSZ 是进程总共有多少虚拟内存。这包括所有类型的内存,包括 RAM 中的和换出的。这些数字可能会出现偏差,因为它们还包括共享库和其他类型的内存。您可以bash运行500 个实例,它们的内存占用的总大小不会是它们的 RSS 或 VSZ 值的总和。
如果您需要更详细地了解进程的内存占用,您有一些选择。你可以通过/proc/$PID/map并剔除你不喜欢的东西。如果它是共享库,计算可能会根据您的需要变得复杂(我想我记得)。
如果你只关心进程的堆大小,你总是可以只解析文件中的[heap]条目map。内核为进程堆分配的大小可能反映也可能不反映进程要求分配的确切字节数。有一些细节、内核内部和优化可以解决这个问题。在理想情况下,它将与您的进程需要一样多,四舍五入到系统页面大小的最接近倍数(getconf PAGESIZE会告诉您它是什么——在 PC 上,它可能是 4,096 字节)。
如果您想查看进程分配了多少内存,最好的方法之一是放弃内核端指标。相反,您可以使用该LD_PRELOAD机制检测 C 库的堆内存(解除)分配函数。就个人而言,我略微滥用valgrind以获取有关此类事情的信息。(请注意,应用检测将需要重新启动该过程。)
请注意,由于您也可能对运行时进行基准测试,这valgrind会使您的程序稍微变慢(但可能在您的容差范围内)。
Cir*_*郝海东 11
最小的可运行示例
为此,您必须了解分页的基础知识:https : //stackoverflow.com/questions/18431261/how-does-x86-paging-work,特别是操作系统可以通过页表分配虚拟内存/它的内部内存簿记(VSZ 虚拟内存),然后才实际在 RAM 或磁盘(RSS 驻留内存)上有后备存储。
现在为了观察这一点,让我们创建一个程序:
mmap主文件
#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;
/* /sf/ask/109088171/#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:
* /sf/ask/109088171/ */
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;
}
Run Code Online (Sandbox Code Playgroud)
编译并运行:
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
Run Code Online (Sandbox Code Playgroud)
在哪里:
echo 1 | sudo tee /proc/sys/vm/overcommit_memory: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
Run Code Online (Sandbox Code Playgroud)
退出状态:
137
Run Code Online (Sandbox Code Playgroud)
其中由128点+信号编号规则的手段,我们得到的信号数9,这man 7 signal说的是SIGKILL,这是由Linux发外的内存杀手。
输出解释:
printf '0x%X\n' 0x40009A4 KiB ~= 64GiB(ps值以 KiB 为单位)。extra_memory_committed 0,这意味着我们还没有触及任何页面。RSS 是一个小型的1648 KiB,已分配给正常的程序启动,如文本区域、全局变量等。8388608 KiB == 8GiB很多页。结果,RSS 增加了 8GIB 到8390256 KiB == 8388608 KiB + 1648 KiBOOM 杀手日志
我们的dmesg命令已经显示了 OOM 杀手日志。
已经在以下位置询问了对这些的确切解释:
日志的第一行是:
[ 7283.479087] mongod invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0
Run Code Online (Sandbox Code Playgroud)
所以我们看到有趣的是,首先触发 OOM 杀手的是始终在我的笔记本电脑中后台运行的 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
Run Code Online (Sandbox Code Playgroud)
再往前走,我们看到我们自己的小家伙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
Run Code Online (Sandbox Code Playgroud)
该日志提到了score 865该进程具有的最高(最差)OOM 杀手分数,如:OOM 杀手如何决定首先杀死哪个进程?
同样有趣的是,一切显然发生得如此之快,以至于在释放的内存被计算出来之前,进程oom再次唤醒了它DeadlineMonitor:
[ 7283.481043] DeadlineMonitor invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0
Run Code Online (Sandbox Code Playgroud)
这一次杀死了一些 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
Run Code Online (Sandbox Code Playgroud)
在 Ubuntu 19.04、Linux 内核 5.0.0 中测试。