我观察到以下无法解释的行为:服务器报告的可用物理内存量增加,而最耗内存的进程(Web 服务器进程)报告的“Res”内存几乎持平。
我主要想了解的是:进程报告的驻留内存保持不变,而物理内存使用量却增加,这怎么可能呢?这些进程内部可能发生了什么,导致这种可观察到的行为,尤其是在没有产生太多负载的情况下?
换句话说:在一个进程内部会发生什么,例如“内存”最初被报告为“常驻”,但实际上并未占用任何物理内存,而现在它仍然被报告为“常驻”,但现在实际上也占用了物理内存?
示例:我有一台内存为 2GB 的虚拟服务器。昨天 12:00,据top
/ free
[1] 报告,大约有 800MB(40%)正在使用中。大部分由几个进程使用,它们总共报告使用了大约 1.2GB 的常驻内存[2]。
然后我开始进行一些测试(执行由这些进程提供的大量 HTTP 请求),将物理内存使用量提高到 1.2GB(60%),并将进程使用的常驻内存增加到 3.2GB。之后,我根本没有碰过服务器,它也不公开可用:之后负载小于 0.03。
然而,虽然进程报告的常驻内存稳定在 3.2GB,但物理内存使用率却缓慢增加,并在某个时候超过 90%(1.8GB),导致标志被触发。在这些 Web 服务器进程中,当时没有发生任何事情(负载证明),也没有任何特殊作业在运行。
可以看到上述场景的图表这里。上图显示的正是top
/free
报告的可用物理内存。下图显示的正是top
“Res”列中报告的内容。请注意,标记的区域Ruby
是 6 个进程的总数。
[1] 通常,在这些服务器上,所有内存都标记为“已使用”,所有可用内存都用于缓存。我所说的全部是指:直到最后一个字节。top
和中的所有其他数字free
均为 0。
[2] 我理解多个进程报告的驻留内存总和可能超过使用的物理内存,但我认为我不知道全部发生这种情况的方式。
答案1
发生这种情况是因为 RSS不是一个权威值,告诉您该程序使用了多少内存。它是该程序映射了多少常驻内存的权威值。两者是有区别的。
RSS 最多只能作为您使用内存量的提示。
内核有很多节省内存的妙招。进程可能会共享大量内存,尤其是分叉的进程。
如果您有一个父进程分配了 100M 的内存,然后生成一个子进程,这两个进程将共享该内存区域,父进程和子进程都将声称 RSS 值 >= 100M,因为它们都映射到同一内存区域。从技术上讲这是正确的,父进程的 RSS >= 100M,因为这就是该进程映射的内存量,和子进程的 RSS 也 >= 100M,因为该进程还有那么多的映射,只是碰巧两个进程共享(大部分)相同的映射。
您可以使用一些简单的 Python 来演示这一点。
#!/usr/bin/python
import os,sys,signal
HOG = 'A' * 104857600 ## 100 MB
try:
for i in range(100):
pid = os.fork()
if pid:
continue
else:
break
signal.pause()
except KeyboardInterrupt:
sys.exit(0)
此程序创建一个 100M 的内存区域,并用“A”填充它。然后它生成 100 个子进程(总共 101 个进程),然后等待 ctrl-c。
这是之前的情景。
$ top -bn1 -u matthew
top - 21:03:04 up 11 min, 1 user, load average: 0.04, 0.08, 0.09
Tasks: 212 total, 1 running, 211 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.7 us, 0.3 sy, 0.0 ni, 98.7 id, 0.2 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 16124248 total, 1513728 used, 14610520 free, 78268 buffers
KiB Swap: 8069116 total, 0 used, 8069116 free, 578148 cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1837 matthew 20 0 767916 5072 3400 S 0.0 0.0 0:00.06 gnome-keyr+
1880 matthew 20 0 13920 608 468 S 0.0 0.0 0:00.00 dbus-launch
1949 matthew 20 0 307180 2804 2312 S 0.0 0.0 0:00.01 gvfsd
2051 matthew 20 0 337684 2908 2436 S 0.0 0.0 0:00.00 at-spi-bus+
2059 matthew 20 0 127260 2920 2360 S 0.0 0.0 0:00.05 at-spi2-re+
2082 matthew 9 -11 486316 7044 4376 S 0.0 0.0 0:00.09 pulseaudio
2121 matthew 20 0 317660 2952 2324 S 0.0 0.0 0:00.00 gvfs-gphot+
2132 matthew 20 0 1440732 105732 30156 S 0.0 0.7 0:09.64 gnome-shell
2145 matthew 20 0 513076 3996 3064 S 0.0 0.0 0:00.00 gsd-printer
2160 matthew 20 0 313300 3488 2940 S 0.0 0.0 0:00.00 ibus-dconf
2172 matthew 20 0 775428 14000 10348 S 0.0 0.1 0:00.05 gnome-shel+
2182 matthew 20 0 319120 7120 5444 S 0.0 0.0 0:00.07 mission-co+
2196 matthew 20 0 232848 2708 2164 S 0.0 0.0 0:00.00 gvfsd-meta+
2206 matthew 20 0 408000 11828 8084 S 0.0 0.1 0:00.06 abrt-applet
2209 matthew 20 0 761072 15120 10680 S 0.0 0.1 0:00.13 nm-applet
2216 matthew 20 0 873088 14956 10600 S 0.0 0.1 0:00.09 evolution-+
2224 matthew 20 0 1357640 29248 14052 S 0.0 0.2 0:00.26 evolution-+
2403 matthew 20 0 295036 6680 3876 S 0.0 0.0 0:00.01 telepathy-+
2475 matthew 20 0 380916 2756 2264 S 0.0 0.0 0:00.00 gvfsd-burn
2486 matthew 20 0 8460 736 608 S 0.0 0.0 0:00.00 gnome-pty-+
2617 matthew 20 0 116412 3068 1596 S 0.0 0.0 0:00.04 bash
2888 matthew 20 0 457196 9868 5164 S 0.0 0.1 0:00.05 telepathy-+
3347 matthew 20 0 123648 1400 1020 R 0.0 0.0 0:00.00 top
顶部显示14610520 KB 可用内存。
让我们运行我们的程序:
$ python trick_rss.py & top -bn1 -u matthew
[2] 3465
top - 21:04:54 up 13 min, 1 user, load average: 0.05, 0.07, 0.08
Tasks: 415 total, 1 running, 414 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.7 us, 0.3 sy, 0.0 ni, 98.8 id, 0.2 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 16124248 total, 1832040 used, 14292208 free, 78320 buffers
KiB Swap: 8069116 total, 0 used, 8069116 free, 578144 cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3465 matthew 20 0 227652 106676 1792 S 31.7 0.7 0:00.05 python
2483 matthew 20 0 641568 18736 11656 S 6.3 0.1 0:01.26 gnome-term+
1837 matthew 20 0 767916 5072 3400 S 0.0 0.0 0:00.06 gnome-keyr+
1880 matthew 20 0 13920 608 468 S 0.0 0.0 0:00.00 dbus-launch
1949 matthew 20 0 307180 2804 2312 S 0.0 0.0 0:00.01 gvfsd
2051 matthew 20 0 337684 2908 2436 S 0.0 0.0 0:00.00 at-spi-bus+
2059 matthew 20 0 127260 2920 2360 S 0.0 0.0 0:00.05 at-spi2-re+
2082 matthew 9 -11 486316 7044 4376 S 0.0 0.0 0:00.09 pulseaudio
2121 matthew 20 0 317660 2952 2324 S 0.0 0.0 0:00.00 gvfs-gphot+
2136 matthew 20 0 178692 2588 1788 S 0.0 0.0 0:00.00 dconf-serv+
2145 matthew 20 0 513076 3996 3064 S 0.0 0.0 0:00.00 gsd-printer
2160 matthew 20 0 313300 3488 2940 S 0.0 0.0 0:00.00 ibus-dconf
2172 matthew 20 0 775428 14000 10348 S 0.0 0.1 0:00.05 gnome-shel+
2182 matthew 20 0 319120 7120 5444 S 0.0 0.0 0:00.07 mission-co+
2196 matthew 20 0 232848 2708 2164 S 0.0 0.0 0:00.00 gvfsd-meta+
2206 matthew 20 0 408000 11828 8084 S 0.0 0.1 0:00.06 abrt-applet
2209 matthew 20 0 761072 15120 10680 S 0.0 0.1 0:00.14 nm-applet
2216 matthew 20 0 873088 14956 10600 S 0.0 0.1 0:00.10 evolution-+
2224 matthew 20 0 1357640 29248 14052 S 0.0 0.2 0:00.26 evolution-+
2403 matthew 20 0 295036 6680 3876 S 0.0 0.0 0:00.01 telepathy-+
2475 matthew 20 0 380916 2756 2264 S 0.0 0.0 0:00.00 gvfsd-burn
2487 matthew 20 0 116544 3316 1716 S 0.0 0.0 0:00.09 bash
2804 matthew 20 0 1239196 275576 41432 S 0.0 1.7 0:25.54 firefox
2890 matthew 20 0 436688 15932 7288 S 0.0 0.1 0:00.05 telepathy-+
3360 matthew 20 0 227652 106680 1792 S 0.0 0.7 0:00.05 python
3366 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3368 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3370 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3372 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3374 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3376 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3378 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3380 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3382 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3384 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3386 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3388 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3390 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3392 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3394 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3396 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3398 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3400 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3402 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3404 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3406 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3408 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3410 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3412 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3414 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3416 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3418 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3420 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3422 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3424 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3426 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3428 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3430 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3432 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3434 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3436 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3438 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3440 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3442 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3444 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3446 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3448 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3450 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3452 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3454 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3456 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3458 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3460 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3462 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3464 matthew 20 0 227652 105096 208 S 0.0 0.7 0:00.00 python
3467 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3469 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3471 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3473 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3475 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3477 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3479 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3481 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3483 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3485 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3487 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3489 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3491 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3493 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3495 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3497 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3499 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3501 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3503 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3505 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3507 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3509 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3511 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3513 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3515 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3517 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3519 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3521 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3523 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3525 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3527 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3529 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3531 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3533 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3535 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3537 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3539 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3541 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3543 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3545 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3547 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3549 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3551 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3553 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3555 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3557 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3559 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3561 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3563 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
3565 matthew 20 0 227652 105092 208 S 0.0 0.7 0:00.00 python
我有 14292208 Kb 可用空间。大约 300M 内存已被使用。但是,如果我按照 RSS 告诉我的,我实际上已经使用了 10GB 内存!
最后,如果您看一下进程映射,您会发现虚拟内存地址彼此相同。
$ pmap -x 3561
...
00007f05da5e8000 102404 102404 102404 rw--- [ anon ]
...
$ pmap -x 3565
...
00007f05da5e8000 102404 102404 102404 rw--- [ anon ]
...
懒惰复制
此 C 程序演示了惰性复制的发生,在这种情况下,所有进程都映射到同一内存区域,但子进程已覆盖内容。在后台,内核已将这些页面重新映射到实际内存中的不同位置,但显示相同的虚拟地址空间。
现在,每个实例确实占用内存,但 RSS 值保持不变。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
int main() {
int i;
char c=65;
pid_t pid;
signal(SIGCHLD, SIG_IGN);
/* Allocate some memory */
char *hog = malloc(104857600);
memset(hog, c, 104857600);
for (i=1; i < 4; i++) {
if (fork())
continue;
memset(hog, c+i, 104857600);
break;
}
sleep(3);
printf("Pid %d shows HOG[1048576] saying %c\n", getpid(), hog[1048576]);
pause();
}
用 进行编译gcc -o trick_rss trick_rss.c
。并用 运行free -m; ./trick_rss & sleep 5; free -m
。
您将获得以下结果;
$ free -m; ./trick_rss & sleep 5; free -m
total used free shared buffers cached
Mem: 15746 2477 13268 0 79 589
-/+ buffers/cache: 1808 13938
Swap: 7879 0 7879
[3] 4422
Pid 4422 shows HOG[1048576] saying A
Pid 4424 shows HOG[1048576] saying B
Pid 4425 shows HOG[1048576] saying C
Pid 4426 shows HOG[1048576] saying D
total used free shared buffers cached
Mem: 15746 2878 12867 0 79 589
-/+ buffers/cache: 2209 13536
Swap: 7879 0 7879
答案2
随着 ruby(或其他)进程之间共享的内存量减少,使用的物理内存量可能会增加。但是,就你的情况而言,系统处于空闲状态,因此你不会期望任何变化。可能是 ruby 垃圾收集器导致共享减少,因为这句话来自http://www.rubyenterpriseedition.com/faq.html说的是:
因此,垃圾收集周期将导致所有对象被写入(或者用操作系统术语来说:对象的内存页面被弄脏)。操作系统将复制所有内存,从而抵消写时复制的效果。
在这段时间内共享的内存量是多少?