Top和Free命令中的内存使用信息怎么那么怪

转自 

http://linmingren.me/blog/2014/03/top%E5%92%8Cfree%E5%91%BD%E4%BB%A4%E4%B8%AD%E7%9A%84%E5%86%85%E5%AD%98%E4%BD%BF%E7%94%A8%E4%BF%A1%E6%81%AF%E6%80%8E%E4%B9%88%E9%82%A3%E4%B9%88%E6%80%AA/

这几天搞性能测试,在用Top和Free命令来查看进程所使用的内存信息时发现了一些以前没注意到的东西。先用下面这个最简单的例子来说明一下top中的VIRT和RES以及Swap所代表的意思。

#include <iostream>
using namespace std;
 
int main() {
    char c;
    char * buf;
    while (1) {
        cin >> c;
        //每次new 200M
        buf = new char[1024 * 1024 * 200]; 
    }
    return 0;
}

在我机器上运行后,按下第一个字符之前的Top的输出是 (进程的名字是Memory, 先ps出进程号,然后用top -p 进程号 查看)

KiB Mem: 3921504 total, 2642932 used, 1278572 free, 242396 buffers 
KiB Swap: 4065276 total, 0 used, 4065276 free, 1203440 cached

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7033 dlin 20 0 12528 1064 896 S 0.0 0.0 0:00.00 Memory

Free的输出是

total used free shared buffers cached 
Mem: 3829 2584 1244 0 236 1179
-/+ buffers/cache: 1168 2661
Swap: 3969 0 3969

 输入一个字符后,top的输出是

KiB Mem: 3921504 total, 2653400 used, 1268104 free, 242764 buffers 
KiB Swap: 4065276 total, 0 used, 4065276 free, 1208860 cached
 
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7033 dlin 20 0 212m 1064 896 S 0.0 0.0 0:00.00 Memory

free的输出是

total used free shared buffers cached 
Mem: 3829 2593 1235 0 237 1181
-/+ buffers/cache: 1174 2654
Swap: 3969 0 3969

这时top中如果只看%MEM的话,就会以为这个进程没有用什么内存,虽然实际上已经分配了200M,而free中used的物理内存的大小几乎没变,结论是new出来的内存,如果你没有使用它,那么就不会驻留在物理内存中。怎么使用这块内存呢,直接用memset给它设些值就行。

把代码加一行,改成这样:

#include <iostream>
#include <cstring>
using namespace std;
 
int main() {
    char c;
    char * buf;
    while (1) {
        cin >> c;
        //每次new 200M
        buf = new char[1024 * 1024 * 200]; 
        //只使用其中的100M
        memset(buf,'a',1024 * 1024 * 100);
    }
    return 0;
}

这次的top就看到%MEM有值了,而且驻留内存(RES)是100M,刚好是我们memset的大小。

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7504 dlin 20 0 212m 101m 964 S 0.0 2.6 0:00.04 Memor

free的输出也可以看到used的内存多了差不多100M

total used free shared buffers cached 
Mem: 3829 2736 1093 0 238 1203
-/+ buffers/cache: 1295 2534
Swap: 3969 0 3969

到了这里VIRT和RES的含义就清晰了:

VIRT: 就是你代码new或者malloc的内存的大小
RES: 你真正使用的内存的大小,如果你new出来,但没有使用,那么这个值会比较小。

接下来看Swap的意思,其实从字面意思大概可以猜出来这应该是物理内存不够时,系统把一部分内存置换到硬盘上的大小。因为我们还没有用完物理内存,所以top命令输出中的Swap就是0. 让我们不断运行我们的程序,看看要分配几次200M才会让Swap的值不是0.当new了5G (注意物理内存只有不到3G多),使用了2.5G的时候去看top的输出,发现有500M (500776 used)的内存已经被置换到硬盘上去了,这时候我的电脑作什么都变得很慢(风扇的声音大了好多),因为这时候new的内存都是从硬盘映射过来的。

KiB Mem: 3921504 total, 3792944 used, 128560 free, 296 buffers
KiB Swap: 4065276 total, 500776 used, 3564500 free, 182828 cached 
 
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7504 dlin 20 0 5212m 2.5g 204 S 0.0 67.9 0:01.35 Memor

在启动swap的64位系统上,想要搞个bad_alloc异常不是很容易。不过我们可以关闭swap,

sudo swapoff -a
跑完这个命令,再去看top的输出就发现里里面的可用的Swap大小变成了0. 现在再跑我们的程序,在输入23个字符后 (也就是new 了4.6G,使用了2.3G),终于看到了预期中的内存不够异常
terminate called after throwing an instance of 'std::bad_alloc' 
what(): std::bad_alloc
gAborted (core dumped)

如果我们只new,而不使用内存,一样会得到bad_alloc异常,像下面改动后的代码,直接new 4G内存会马上出错 (前提是调用了swapoff)。

#include <iostream>
#include <cstring>
using namespace std;
 
int main() {
    char c;
    char * buf;
    while (1) {
        cin >> c;
        //new 4G
        buf = new char[1024 * 1024 * 4000]; 
        //只使用其中的100M
        //memset(buf,'a',1024 * 1024 * 100); 
    }
    return 0;
}

 

 
posted @ 2016-02-02 17:39  princessd8251  阅读(527)  评论(0)    收藏  举报