首页 > 代码库 > 从一道面试题(死循环里分配内存)阐述Linux的内存管理

从一道面试题(死循环里分配内存)阐述Linux的内存管理

题目:

int cnt = 0;  

while(1) { 

    ++cnt;
    ptr = (char *)malloc(1024*1024*128);
    if(ptr == NULL) {
      printf("%s\n", "is null");
      break;
    }
  }
  printf("%d\n", cnt);

这个程序会有怎样的输出呢?


结果在Linux32位机是

is null

3057


为嘛是3057??

因为用户态虚拟内存地址空间是3G。

3057M 大概就是 3G。

可见malloc时是在虚拟地址空间申请的。具体就是处理一下vm_area_struct。

由于代码里并没有对申请的地址进行访问,所以是不会分配物理内存的。

直到对地址进行访问,由于缺页中断才开始处理页表映射,然后分配物理内存。


那么可以分配多少物理内存呢?也就是如果程序是这样的:

int cnt = 0;  

while(1) { 

    ++cnt;
    ptr = (char *)malloc(1024*1024*128);
    if(ptr == NULL) {
      printf("%s\n", "is null");
      break;
    }else {

      memset(ptr, ‘\0‘, 1024*1024*128);

    }
  }
  printf("%d\n", cnt);

这个程序会有怎样的输出呢?


这又取决于Linux的内核参数和目前剩余的内存啦!!!!!

主要是这个参数overcommit_memory【1】【2】: 

CommitLimit和Committed_As参数。

CommitLimit是一个内存分配上限,CommitLimit = 物理内存 * overcommit_ratio(默认50,即50%) + swap大小

Committed_As是已经分配的内存大小。

overcommit_memory参数就是控制分配内存是否可以超过CommitLimit,默认是0,即启发式的overcommitting handle,会尽量减少swap的使用,root可以分配比一般用户略多的内存。1表示允许超过CommitLimit,2表示不允许超过CommitLimit。


对应于上面的程序有何表现呢?

如果是0,那么就会把所有的swap+memory用光才会返回NULL(此处假设虚拟空间没用完,如果是虚拟空间用完而物理空间没用完,当然也是返回NULL)。

如果是1,那么同样会把所有的swap+memory用光才会返回NULL(此处假设虚拟空间没用完,如果是虚拟空间用完而物理空间没用完,当然也是返回NULL)。

啊!那么0和1还有啥区别呢?(表示不理解,从实验结果来看是没什么区别的,但是文档说明为以下内容,如果你明白,请一定告诉我,谢谢。)

0   -   Heuristic overcommit handling. Obvious overcommits of

        address space are refused. Used for a typical system. It

        ensures a seriously wild allocation fails while allowing

        overcommit to reduce swap usage.  root is allowed to

        allocate slightly more memory in this mode. This is the

        default.

 

1   -   Always overcommit. Appropriate for some scientific

        applications.


如果是2,那么就会把所有的swap+overcommit*ratiomemory用光马上就会返回NULL(此处假设虚拟空间没用完,如果是虚拟空间用完而物理空间没用完,当然也是返回NULL)。


文档【3】更详细地阐述了Linux内存的使用。


【1】http://yinjiaoyuan.blog.163.com/blog/static/1431931222012117540582/

【2】http://blog.csdn.net/jollyjumper/article/details/24127009

【3】http://www.win.tue.nl/~aeb/linux/lk/lk-9.html#ss9.6