比较虚拟内存大小与常驻内存大小

比较虚拟内存大小与常驻内存大小

我偶然看到了这个 stackoverflow 帖子:

https://stackoverflow.com/questions/10400751/how-do-vmrss-and-resident-set-size-match

投票正确的答案陈述如下:

“因此,VSS 应该大于 RSS。如果它们接近相等,则意味着您的进程在内存中处于舒适状态。如果 VSS 大得多,则意味着内存不足,部分内存必须交换到磁盘(即,由于竞争进程等)。”

这句话让我很困惑,因为当我检查我的系统时,我注意到了以下情况。

首先,我注意到我有很多可用内存:

$ cat /proc/meminfo
MemTotal:        6113156 kB
MemFree:         3668992 kB

这意味着我有 3.5 GB 的纯内存(没有交换、没有磁盘等)

然而,当我查看我生成的 apache2 子进程时,我感到惊讶:

$ ps aux | grep apache2
USER       PID  %CPU %MEM  VSZ  RSS     TTY   STAT START    TIME    COMMAND
root      1130  0.0  0.1 149080 10600 ?        Ss   Jul11   0:03 /usr/sbin/apache2 -k start
www-data 23211  0.0  0.3 163408 23784 ?        S    10:34   0:03 /usr/sbin/apache2 -k start
www-data 23215  0.0  0.4 164436 24832 ?        S    10:34   0:02 /usr/sbin/apache2 -k start
www-data 23287  0.0  0.3 163608 23992 ?        S    10:36   0:02 /usr/sbin/apache2 -k start
www-data 23351  0.0  0.3 163660 24064 ?        S    10:40   0:01 /usr/sbin/apache2 -k start
www-data 23440  0.0  0.3 161580 23588 ?        S    10:46   0:00 /usr/sbin/apache2 -k start
www-data 24393  0.0  0.3 163620 23496 ?        S    11:32   0:00 /usr/sbin/apache2 -k start
www-data 25377  0.0  0.2 150656 12316 ?        S    12:20   0:00 /usr/sbin/apache2 -k start
www-data 25378  0.0  0.3 158224 18400 ?        S    12:20   0:00 /usr/sbin/apache2 -k start
www-data 27038  0.0  0.1 149360  7816 ?        S    13:01   0:00 /usr/sbin/apache2 -k start
www-data 27041  0.0  0.1 149368  7660 ?        S    13:01   0:00 /usr/sbin/apache2 -k start
1000     27124  0.0  0.0   8112   900 pts/0    S+   13:04   0:00 grep apache2

(请注意,grep 会删除列标题,因此我人为地将它们添加回去)

看看虚拟内存与常驻内存相比有多大。我的意思是,例如对于 apache 父进程(父进程是 1130):

$ ps xao pid,ppid,pgid,sid,comm | grep apache2 
 1130     1  1130  1130 apache2
23211  1130  1130  1130 apache2
23440  1130  1130  1130 apache2
27038  1130  1130  1130 apache2
27041  1130  1130  1130 apache2
27183  1130  1130  1130 apache2
27242  1130  1130  1130 apache2
27349  1130  1130  1130 apache2
27405  1130  1130  1130 apache2
27456  1130  1130  1130 apache2
27457  1130  1130  1130 apache2

该父进程占用了 146 兆字节的虚拟内存,而常驻内存只占用了 10 兆字节。也就是说,使用的交换空间有 136 兆字节的差异!

所以这对我来说没有意义。我有这么多的可用内存,但它却使用了这么多的交换空间??根据 stackoverflow 上的帖子,他说“意味着没有足够的内存”。但事实并非如此。我有足够的内存。

答案1

SO 帖子得出的“换出”结论是错误的。例如,这是一个简单的程序:

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    printf("Started - sleeping 10s; pid = %i\n", (int)getpid());
    sleep(10);

    int fd = open("10469068800-byte-file", O_RDONLY);
    void *map = mmap(NULL, 10469068800, PROT_READ, MAP_SHARED, fd, 0);

    printf("Mapped - sleeping 10s; fd %i to %p\n", fd, map);
    sleep(10);

    return 0;
}

当我打印ps开始消息(在映射信息):

anthony@Zia:~$ ps u 13420
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
anthony  13420  0.0  0.0   4080   348 pts/13   S+   16:10   0:00 ./test

之后:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
anthony  13420  0.0  0.0 10227780 348 pts/13   S+   16:10   0:00 ./test

程序的部分地址空间目前位于磁盘上,但这是因为它是一个尚未读取(或可能永远不会读取)的内存映射文件。此程序也发生了类似的事情:

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    printf("Started - sleeping 10s; pid = %i\n", (int)getpid());
    sleep(10);

    void *mem = malloc(1024*1024*1024);

    printf("Allocated - sleeping 10s; mem at %p\n", mem);
    sleep(10);

    return 0;
}

前:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
anthony  15150  0.0  0.0   4080   352 pts/13   S+   16:18   0:00 ./test2

后:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
anthony  15150  0.0  0.0 1052660  352 pts/13   S+   16:18   0:00 ./test2

在这种情况下,内存已分配,但作为优化,内核实际上不会将实际的内存页面放在这些地址后面,直到程序使用它们为止。因此,您再次看到 VSZ 比 RSS 高得多。

您可能在 Apache 中看到了上述两件事(也许还有更多)。您可以使用pmap -x来判断。以下是第二个程序(malloc 程序)的样子:

anthony@Zia:~$ pmap -x 15997
15997:   ./test2
Address           Kbytes     RSS   Dirty Mode   Mapping
0000000000400000       4       4       0 r-x--  test2
0000000000600000       4       4       4 rw---  test2
00007fba82f94000 1048580       4       4 rw---    [ anon ]      <--- HERE
00007fbac2f95000    1672     300       0 r-x--  libc-2.17.so
00007fbac3137000    2048       0       0 -----  libc-2.17.so
00007fbac3337000      16      16      16 r----  libc-2.17.so
00007fbac333b000       8       8       8 rw---  libc-2.17.so
00007fbac333d000      16      12      12 rw---    [ anon ]
00007fbac3341000     132     104       0 r-x--  ld-2.17.so
00007fbac3533000      12      12      12 rw---    [ anon ]
00007fbac355f000      12      12      12 rw---    [ anon ]
00007fbac3562000       4       4       4 r----  ld-2.17.so
00007fbac3563000       8       8       8 rw---  ld-2.17.so
00007fffb7163000     132      12      12 rw---    [ stack ]
00007fffb71fe000       8       4       0 r-x--    [ anon ]
ffffffffff600000       4       0       0 r-x--    [ anon ]
----------------  ------  ------  ------
total kB         1052660     504      92

请注意,您可以看到匿名映射非常大,但几乎没有任何常驻内容。对于带有 的程序mmap,您将获得:

Address           Kbytes     RSS   Dirty Mode   Mapping
00007f8e50cf2000 10223700       0       0 r--s-  10469068800-byte-file

这表明内存映射文件存在,但它并不驻留。

相关内容