Linux如何使用总计超过100%的内存

需求提出:数据库snapshot

之所以有这个需求,是因为我手头有一个数据库工程,我们打snapshot的时候,是在愿进程调用一个fork,构造了一个子进程,在子进程dump数据的。但是数据库嘛,吃内存是肯定的,于是在我的渣渣虚拟机上,就遇到了内存占用在top观察超过60%,没法fork进行snapshot的窘境。

于是我就想到这个问题:难道一个内存占用超过一定比例的进程,不能调用fork??毕竟,fork会拥有原进程所有的资料,只是fork之后新的进程只拥有当前运行的线程。所以fork之后,两个进程在top里看起来因该是一样的。那么,到底有没有可能,fork之后,两个进程加起来,memory百分比超过100呢?

观点一:必须可以,有虚拟内存映射

我写了个简单的代码,进行测试:

#include <unistd.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    int j = 1024 * atoi(argv[1]);
    while(j--)
    {
        int *x = (int*)malloc(1024 * 1024);
        memset(x, 0, 1024 * 1024);//注意这里一定要memset才会实际申请内存,否则只会是虚拟内存
    }
    printf("now ready to fork!\n");
    sleep(10);
    int pid = fork();
    if(pid == 0)
    {
        sleep(5);
        printf("child\n");
    }else if(pid == -1)
    {
        sleep(2);
        printf("fork failed:%d, %s\n", errno, strerror(errno));
    }else
    {
        printf("child pid:%d\n", pid);
        wait(pid);
        sleep(10);
    }
    return 0;
}

编译运行,参数为申请内存数量,单位为MB,我在一个6GB内存,1GB缓存的机器上测试,得到这样的结果:

➜  fork ./a.out 3000
now ready to fork!
fork failed:12, Cannot allocate memory

嗯,申请3000MB内存就gg了。实际内存占用在top里面看,刚好是51%,有兴趣的可以自己测试下。

观点二:不可以,top里面看到的内存总和不能超过100%

实际上如果我不懂Linux内存管理,我也会这么认为,但是考虑到Linux的以下特性,我无论如何都不能接收这个答案:

  • 交换分区,允许将内存换出到磁盘
  • 延后分配,只在实际使用的时候分配内存(也就是为什么要调用memeset)
  • Copy On Write,这个是最重要的,理论来说,fork的时候不拷贝内存,只在新进程需要修改对应区域的时候,才申请内存。但是这个fork调用,在调用的时候直接失败了,甚至都没有尝试fork一下。

综上所述,其实如果我fork一个进程,在子进程我不做任何操作,Linux实际上一点额外内存都不需要分配,不应该在fork的时候就失败,哪怕真的后面内存不够用了,也应该fork之后在算账啊。

答案揭晓:overcommit_memory

Linux内核实际上有一个选项专门解决这个问题:

/proc/sys/vm/overcommit_memory

该选项默认为0,如果该选项为1,则表示允许从一个高内存的进程fork一个子进程,两个进程加起来可以超过100%内存

有兴趣的同学可以试一下,将他设置为1,就可以在top里面看到memory的百分比加起来超过100%的景象了。

猜你喜欢

转载自blog.csdn.net/zerooffdate/article/details/79577708