1、问题现象和分析:
测试时发现当系统中空闲内存还有很多时,就报内存分配失败了,所有进程都报内存分配失败:
sshd@localhost:/var/log>free
             total       used       free     shared    buffers     cached
Mem:      12183700    8627972    3555728          0     289252     584444
-/+ buffers/cache:    7754276    4429424
Swap:            0          0          0
sshd@localhost:/var/log>free
-bash: fork: Cannot allocate memory
sshd@localhost:/var/log>cat /proc/meminfo
-bash: fork: Cannot allocate memory

而messages日志中,也没有OOM相关的记录。最后确认原因为:/proc/sys/vm/overcommit_memory参数导致。
该环境中该参数设置为2,表示“No overcommit”,即系统中所有进程占用的虚拟内存空间不能超过上限:
cat /proc/meminfo
CommitLimit:    12061860 kB  //虚拟地址空间的上限
Committed_AS:    8625360 kB  //当前的使用量

而该参数应该默认是0,这种情况下,只有还有空闲的物理内存,就可以继续分配,不受虚拟地址空间的限制。
echo 0 > /proc/sys/vm/overcommit_memory
如此修正后解决。

2、关于overcommit_memory说明:

取值为0,系统在为应用进程分配虚拟地址空间时,会判断当前申请的虚拟地址空间大小是否超过剩余内存大小,如果超过,则虚拟地址空间分配失败。因此,也就是如果进程本身占用的虚拟地址空间比较大或者剩余内存比较小时,fork、malloc等调用可能会失败。

取值为1,系统在为应用进程分配虚拟地址空间时,完全不进行限制,这种情况下,避免了fork可能产生的失败,但由于malloc是先分配虚拟地址空间,而后通过异常陷入内核分配真正的物理内存,在内存不足的情况下,这相当于完全屏蔽了应用进程对系统内存状态的感知,即malloc总是能成功,一旦内存不足,会引起系统OOM杀进程,应用程序对于这种后果是无法预测的

取值为2,则是根据系统内存状态确定了虚拟地址空间的上限,由于很多情况下,进程的虚拟地址空间占用远大小其实际占用的物理内存,这样一旦内存使用量上去以后,对于一些动态产生的进程(需要复制父进程地址空间)则很容易创建失败,如果业务过程没有过多的这种动态申请内存或者创建子进程,则影响不大,否则会产生比较大的影响

3、相应代码分析:

点击(此处)折叠或打开

  1. int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
  2. {
  3. unsigned long free, allowed;
  4. vm_acct_memory(pages);
  5. /*
  6. * Sometimes we want to use more memory than we have
  7. */
  8. if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) //overcommit_memory=1,直接返回成功,不做任何限制。
  9. return 0;
  10. if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { //overcommit_memory=0,启发式方式,根据当前系统中空闲内存状况来决定是否可以分配内存。
  11. unsigned long n;
  12. free = global_page_state(NR_FILE_PAGES);
  13. free += nr_swap_pages;
  14. /*
  15. * Any slabs which are created with the
  16. * SLAB_RECLAIM_ACCOUNT flag claim to have contents
  17. * which are reclaimable, under pressure. The dentry
  18. * cache and most inode caches should fall into this
  19. */
  20. free += global_page_state(NR_SLAB_RECLAIMABLE);
  21. /*
  22. * Leave the last 3% for root
  23. */
  24. if (!cap_sys_admin)
  25. free -= free / 32; //root用户可以在free更少(3%)的时候,分配内存。
  26. if (free > pages) // pages为需要分配的内存大小,free为根据一定规则算出来的“空闲内存大小”,第一次free仅为NR_FILE_PAGES+NR_SLAB_RECLAIMABLE,由于直接或者系统中“实际空闲”内存代价比较大,所以进行分阶判断,提高效率。
  27. return 0;
  28. /*
  29. * nr_free_pages() is very expensive on large systems,
  30. * only call if we're about to fail.
  31. */
  32. n = nr_free_pages(); //当第一次判断不满足内存分配条件时,再进行“实际空闲”内存的获取操作。
  33. /*
  34. * Leave reserved pages. The pages are not for anonymous pages.
  35. */
  36. if (n <= totalreserve_pages)
  37. goto error;
  38. else
  39. n -= totalreserve_pages;
  40. /*
  41. * Leave the last 3% for root
  42. */
  43. if (!cap_sys_admin)
  44. n -= n / 32;
  45. free += n;
  46. if (free > pages)
  47. return 0;
  48. goto error;
  49. }
  50. allowed = (totalram_pages - hugetlb_total_pages()) //当overcommit_memory=2时,根据系统中虚拟地址空间的总量来进行限制。
  51. * sysctl_overcommit_ratio / 100;
  52. /*
  53. * Leave the last 3% for root
  54. */
  55. if (!cap_sys_admin)
  56. allowed -= allowed / 32;
  57. allowed += total_swap_pages;
  58. /* Don't let a single process grow too big:
  59. leave 3% of the size of this process for other processes */
  60. if (mm)
  61. allowed -= mm->total_vm / 32;
  62. if (percpu_counter_read_positive(&vm_committed_as) < allowed)
  63. return 0;
  64. error:
  65. vm_unacct_memory(pages);
  66. return -ENOMEM;
  67. }
 
转载自:
http://blog.chinaunix.net/uid-20671208-id-4440244.html

Linux 内存分配失败(关于overcommit_memory)的更多相关文章

  1. 深入理解Linux内存分配

    深入理解Linux内存分配 为了写一个用户层程序,你也许会声明一个全局变量,这个全局变量可能是一个int类型也可能是一个数组,而声明之后你有可能会先初始化它,也有可能放在之后用到它的时候再初始化.除此 ...

  2. 从malloc中窥探Linux内存分配策略

        malloc函数是C/C++中常用内存分配库函数,本篇文章将以Linux平台上的malloc为剖析对象,深入了解分配一块内存的旅程. malloc入门      使用malloc,需要包含头文 ...

  3. linux内存分配方法总结【转】

    转自:http://www.bkjia.com/Linuxjc/443717.html 内存映射结构: 1.32位地址线寻址4G的内存空间,其中0-3G为用户程序所独有,3G-4G为内核占有. 2.s ...

  4. linux内存分配与回收

    前言 之前在实习时,听了 OOM 的分享之后,就对 Linux 内核内存管理充满兴趣,但是这块知识非常庞大,没有一定积累,不敢写下,担心误人子弟,所以经过一个一段时间的积累,对内核内存有一定了解之后, ...

  5. linux内存分配

    在linux的内存分配机制中,优先使用物理内存,当物理内存还有空闲时(还够用),不会释放其占用内存,就算占用内存的程序已经被关闭了,该程序所占用的内存用来做缓存使用,对于开启过的程序.或是读取刚存取过 ...

  6. Linux内存分配----SLAB

    动态内存管理 内存管理的目标是提供一种方法,为实现各种目的而在各个用户之间实现内存共享.内存管理方法应该实现以下两个功能: 最小化管理内存所需的时间 最大化用于一般应用的可用内存(最小化管理开销) 内 ...

  7. linux内存分配机制

    这几天在观察apache使用内存情况,所以特意了解了下linux的内存机制,发现一篇写得还不错.转来看看. 一般来说在ps aux中看到的rss就是进程所占用的物理内存.但是如果将所有程序的rss加起 ...

  8. Linux内存分配小结--malloc、brk、mmap【转】

    转自:https://blog.csdn.net/gfgdsg/article/details/42709943 http://blog.163.com/xychenbaihu@yeah/blog/s ...

  9. Linux内存分配机制之伙伴系统和SLAB

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6539590.html  内核内存管理的一项重要工作就是如何在频繁申请释放内存的情况下,避免碎片的产生.这就要求 ...

随机推荐

  1. Java两整数相除保留两位小数

    int num1 = 7; int num2 = 9; // 创建一个数值格式化对象 NumberFormat numberFormat = NumberFormat.getInstance(); / ...

  2. go guid 和uuid生成

    1 安装 开始-运行 输入 cmd 回车 输入 go get -u github.com/typa01/go-utils 安装完毕后 2 使用 a 首先引入包 import (      goutil ...

  3. NIO堆外内存与零拷贝

    重点: 1.0拷贝需要系统支持. 普通内存模型: java线程内存 --> 操作系统内存 --> 硬盘 直接内存模型: java --> 操作系统内存 --> 硬盘 两者对比, ...

  4. Codeforces Round #576 (Div. 1) 简要题解 (CDEF)

    1198 C Matching vs Independent Set 大意: 给定$3n$个点的无向图, 求构造$n$条边的匹配, 或$n$个点的独立集. 假设已经构造出$x$条边的匹配, 那么剩余$ ...

  5. (转) [组合数学] 第一类,第二类Stirling数,Bell数

    一.第二类Stirling数 定理:第二类Stirling数S(p,k)计数的是把p元素集合划分到k个不可区分的盒子里且没有空盒子的划分个数. 证明:元素在哪些盒子并不重要,唯一重要的是各个盒子里装的 ...

  6. elasticsearch 开机自启

    linux下开机自启: 在/etc/init.d目录下新建文件elasticsearch 并敲入shell脚本: #!/bin/sh #chkconfig: #description: elastic ...

  7. android 错误解决

    转自:https://blog.csdn.net/gbstyle/article/details/82926358 错误1: com.android.ddmlib.AdbCommandRejected ...

  8. 在我的电脑中删除wps云文档图标

    在我的电脑中删除wps云文档图标 右键点击win10左下角选择运行,输入regedit打开注册表后,找到以下注册表路径: HKEY_CURRENT_USER\Software\Microsoft\Wi ...

  9. JAVA 插入注解处理器

    JDK1.5后,Java语言提供了对注解(Annotation)的支持 JDK1.6中提供一组插件式注解处理器的标准API,可以实现API自定义注解处理器,干涉编译器的行为. 在这里,注解处理器可以看 ...

  10. kvm第四章-- 虚拟化网络管理