当进程使用的“Res”内存不变时,自由物理内存如何减less?

我观察到我无法解释的以下行为:由服务器报告的可用物理内存量增加,而由大多数耗尽内存的进程(Web服务器进程)报告的“Res”内存几乎是平坦的。

我主要想了解的是:如果物理内存的使用增加,而进程所报告的驻留内存是恒定的,那么怎么可能呢? 在这些过程中会发生什么事情来引起这种可观察到的行为,特别是不会产生太多的负载?

换句话说,在一个过程中会发生什么事情,以至于“记忆”首先被报告为“居民”,但实际上并没有占用任何物理记忆的变化,以至于仍被报告为“居民”,但现在也居然占据了物理内存?

例如:我有一个2GB内存的虚拟服务器。 昨天中午12:00,大约有800MB(40%)正在使用,据报道由top / free [1]。 大多数是由几个进程使用,共同报告使用大约1.2GB的驻留内存[2]。

然后,我开始了一些testing(执行这些进程提供的大量HTTP请求),将物理内存使用率提高到1.2GB(60%),并将进程使用的驻留内存增加到了3.2GB。 之后,我根本没有碰到服务器,也没有公开提供:之后的负载<0.03。

尽pipe如此,虽然由进程报告的常驻内存平均为3.2GB,但物理内存使用缓慢增加,并且有一点超过了90%(1.8GB),导致了标志提升。 在这些Web服务器进程中,当时没有任何事情发生(如负载所certificate的),并且没有任何特殊的作业正在运行。

上面的场景图可以在这里看到。 上图显示的是什么top / free报告为空闲物理内存。 下图显示的是“Res”栏中的top报告。 请注意,标记为Ruby的区域总共是6个进程。

[1]通常在这些服务器上,所有内存被标记为“已使用”,所有空闲内存用于caching。 我的意思是:直到最后一个字节。 topfree所有其他数字都是0。

[2]我知道由几个进程报告的常驻内存的总和可以超过所使用的物理内存,但我不认为我知道所有这些可能发生的方式。

发生这种情况是因为RSS 不是一个权威值,它告诉你该程序正在使用多less内存。 它是该程序映射了多less常驻内存的权威性值。 有一个区别。

RSS最多只能作为提示你正在使用多less内存。

内核有很多技巧来节省内存。 进程可能共享大量的内存,尤其是分叉的进程。

如果你有一个父母分配100M的内存,然后产生一个孩子这两个进程将共享该区域的内存,父母和孩子都会声称具有> = 100M的RSS值,因为他们都映射到相同的记忆区域。 从技术上讲,这是正确的,父进程的RSS大于100M,因为进程已经映射了多less内存,subprocess也有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) 

这个程序创build了一个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程序演示了懒惰复制的发生,在这种情况下,所有进程都映射到同一个内存区域,但是subprocess已经覆盖了内容。 在后台,内核已经将这些页面重新映射到实际内存中的不同位置,但显示的是相同的虚拟地址空间。

现在,每个实例都占用内存,但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 free -m; ./trick_rss & sleep 5; free -m 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 

所使用的物理内存量可能随着ruby(或其他)进程共享的内存数量的减less而增加。 但是,在你的情况下,系统是空闲的,所以你不会指望有任何改变。 可能是ruby垃圾收集器正在导致共享减less从http://www.rubyenterpriseedition.com/faq.html这个引述是说&#xFF1A;

垃圾回收循环会导致所有的对象被写入(或者在操作系统中使用专业术语:对象的内存页被弄脏)。 操作系统将复制所有的内存,从而否定了写入时拷贝的效果。

在这段时间内共享内存的数量是多less?