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. js array 排序

    数据 let data = [ {chinese: '蔡司', english: 'Chase',score:67}, {chinese: '艾伦', english: 'Allen',score:7 ...

  2. python 内置函数和匿名函数

    内置函数 截止到python版本3.6.2,现在python一共为我们提供了68个内置函数.     Built-in Functions     abs() dict() help() min() ...

  3. js的变量类型

    参考网址:https://www.cnblogs.com/focusxxxxy/p/6390536.html (讲的蛮好得,图文并茂,我下面只是总结下) 一:ECMAScirpt 变量的两种数据类型 ...

  4. JS做动态表格

    在后台将数据发送过来后,你需要将这些数据做成表格,实现一般表格管理功能 例如这种数据格式, 首先要创建table 在table中添加thead  在thead中添加tr 循环数组,且创建开头的inpu ...

  5. js入门之内置对象Date

    一. Date对象 Math和Date对象的区别 Math对象和Date对象的区别 Math不是一个构造函数,里面提供的是静态成员 Date是一个构造函数 首先要通过new Date() 来创建日期实 ...

  6. K2 BPM_【解决方案】K2+SAP:端到端无缝集成,为企业全面赋能提速_十年专注业务流程管理系统

    企业数字化转型离不开信息技术的支撑,大部分企业的各项业务都会有专业的系统,比如ERP.BI.CRM等.但这些系统往往由于无法融合,造成信息孤岛.数据断层等问题,这阻碍了企业推动数字化转型的进程.如何实 ...

  7. shell 三剑客之 sed 命令详解

    sed 编辑命令 sed 编辑命令对照表 把 /etc/passwd 文件赋值到当前路径下,进行操作 cp /etc/passwd ./ cat -n passwd sed 删除操作 删除 passw ...

  8. 【leetcode】366.Find Leaves of Binary Tree

    原题 Given a binary tree, collect a tree's nodes as if you were doing this: Collect and remove all lea ...

  9. ubuntu18.04 安装android studio

    首先从官网下载android studio:Android Studio (安装前应先安装JDK环境) 得到android-studio-ide-191.5977832-linux.tar.gz 在安 ...

  10. [#Linux] CentOS 7 配置JDK后,eclipse无法启动,提示jdk路径错误。

    ​​​​ 解决方案:在eclipse的目录下创建一个jre文件夹,在jre文件夹里创建一个jdk的bin目录的链接 1.进入到eclipse目录下,右键在终端打开. 2.创建jre目录:mkdir j ...