什么是overcommit_memory?
1. 前言
在日常的工作中可能我们会经常遇到程序fork失败的问题。遇到fork失败往往有两种可能性:
- 进程数超标:可以通过
cat /proc/sys/kernel/threads-max
查看 - 内存不足
进程数预设值往往很大,几乎不太能超标,所以fork失败的原因大部分都是由于内存不足造成的。
我们知道,由于MMU实现了虚拟地址到物理地址的转换,所以我们在申请虚拟地址时往往可以申请一大块内存,这实际上是对资源的有效利用,毕竟只有内存真正被投入使用时(如memset)才会实际分配物理内存,这种允许内存超额commit的机制就是overcommit_memory。
虚拟内存需要物理内存作为支撑,当分配了太多虚拟内存,导致物理内存不够时,就发生了Out Of Memory。这种允许超额commit的机制就是overcommit。
其调用链关系如下图所示。
从图中我们可以看到,fork一步一步执行到了__vm_enough_memory
,该接口是overcommit的核心。
2. 原理
Linux根据参数vm.overcommit_memory
设置overcommit:
- 0 ——默认值,启发式overcommit,它允许overcommit,但太明显的overcommit会被拒绝,比如malloc一次性申请的内存大小就超过了系统总内存。
- 1 ——Always overcommit. 允许
overcommit
,对内存申请来者不拒。 - 2 ——不允许
overcommit
,提交给系统的总地址空间大小不允许超过。
include/uapi/linux/mman.h
中声明了该宏定义:
#define OVERCOMMIT_GUESS 0
#define OVERCOMMIT_ALWAYS 1
#define OVERCOMMIT_NEVER 2
当sysctl_overcommit_memory
等于OVERCOMMIT_ALWAYS
时,内核的处理方式是直接返回。
if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS)return 0;
当sysctl_overcommit_memory
等于OVERCOMMIT_GUESS
时,主要代码如下:
if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {free = global_page_state(NR_FREE_PAGES);free += global_node_page_state(NR_FILE_PAGES);free -= global_node_page_state(NR_SHMEM);free += get_nr_swap_pages();free += global_page_state(NR_SLAB_RECLAIMABLE);if (free <= totalreserve_pages)goto error;elsefree -= totalreserve_pages;if (!cap_sys_admin)free -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10); /* 为root保留的页数 */if (free > pages)return 0;goto error;
}
其中global_page_state
负责读取vm_zone_stat数组中的各项值。
extern atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS];
NR_FREE_PAGES
:富足的未分配资源;NR_FILE_PAGES
:page cache总和;NR_SHMEM
:进程间的share memory;NR_SLAB_RECLAIMABLE
:slab可回收的页数;totalreserve_pages
:每个zone保留的不能被用户空间分配的页数;get_nr_swap_pages
:针对空闲的swap页数
所以free的计算公式如下:
free = NR_FREE_PAGES + NR_FILE_PAGES - NR_SHMEM + swap_pages + NR_SLAB_RECLAIMABLE
如果此时free小于totalreserve_pages
,则判定内存不足,否则 free -= totalreserve_pages
.
如果是普通进程,则还需要保留admin_reserve_kbytes
(/proc/sys/vm/admin_reserve_kbytes)的free page.
此时free若大于申请的pages,则不会发生overcommit。
当sysctl_overcommit_memory
等于OVERCOMMIT_NEVER
时,相关代码如下:
allowed = vm_commit_limit();if (!cap_sys_admin)allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);if (mm) {reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10);allowed -= min_t(long, mm->total_vm / 32, reserve);}if (percpu_counter_read_positive(&vm_committed_as) < allowed)return 0;
error:vm_unacct_memory(pages);return -ENOMEM;/
unsigned long vm_commit_limit(void)
{unsigned long allowed;if (sysctl_overcommit_kbytes)allowed = sysctl_overcommit_kbytes >> (PAGE_SHIFT - 10);elseallowed = ((totalram_pages - hugetlb_total_pages())* sysctl_overcommit_ratio / 100);allowed += total_swap_pages;return allowed;
}
主要看如下值:
sysctl_overcommit_kbytes
:/proc/sys/vm/overcommit_kbytes的值sysctl_overcommit_ratio
:/proc/sys/vm/overcommit_ratio的值totalram_pages
:可分配的总页数total_swap_pages
:可换出的页数hugetlb_total_pages
:huge page相关sysctl_user_reserve_kbytes
:/proc/sys/vm/user_reserve_kbytes的值,用户空间保留的内存大小vm_committed_as
:保存了当前系统中已经申请的虚拟内存大小
由代码可知,vm_commit_limit
包括两种情况:
- 如果
overcommit_kbytes
不为0, allow值为overcommit_kbytes
的一半; - 如果
overcommit_kbytes
为0,allow值为可管理的总内存与vercommit_ratio
的乘积百分比
3. 设置
那么如何设置overcommit的值呢?有三种方法:
- 编辑**/etc/sysctl.conf** ,改vm.overcommit_memory=1,然后sysctl -p使配置文件生效
- sysctl vm.overcommit_memory=1
- echo 1 > /proc/sys/vm/overcommit_memory
4. 总结
本文通过分析内核代码粗略得分析了overcommit_memory的原理,也为后面的OOM-killer的原理做个铺垫。
什么是overcommit_memory?相关推荐
- 又一次内存分配失败(关于overcommit_memory)
1.问题现象和分析: 测试时发现当系统中空闲内存还有很多时,就报内存分配失败了,所有进程都报内存分配失败: sshd@localhost:/var/log>free t ...
- linux redis WARNING overcommit_memory is set to 0! 解决方案
现象 公司的redis有时background save db不成功,通过log发现下面的告警,很可能由它引起的: [13223] 17 Mar 13:18:02.207 # WARNING over ...
- 有关linux下redis overcommit_memory的问题,以及导致的:Cannot allocate memory问题
背景 公司的redis有时background save db不成功,通过log发现下面的告警,很可能由它引起的: [13223] 17 Mar 13:18:02.207 # WARNING over ...
- linux 的overcommit_memory、overcommit_ratio、swappiness 的说明
vm.overcommit_memory vm.overcommit_memory = 0 vm.overcommit_memory = 1 vm.overcommit_memory = 2 0 默认 ...
- 有关linux下redis overcommit_memory的问题
背景 公司的redis有时background save db不成功,通过log发现下面的告警,很可能由它引起的: [13223] 17 Mar 13:18:02.207 # WARNING over ...
- linux下overcommit_memory的问题
背景 公司的redis有时background save db不成功,通过log发现下面的告警,很可能由它引起的: [13223] 17 Mar 13:18:02.207 # WARNING over ...
- linux内核killler,Linux内核参数overcommit_memory和OOM killer介绍
什么是Linux Overcommit和OOM overcommit_memory是一个内核对内存分配的一种策略,它有三个可选值:0.1.2. 0. 表示内核将检查是否有足够的可用内存供应用进程使用: ...
- overcommit_memory=1是否可以改善服务器内存不足的情况
文档对这个参数的说明: /proc/sys/vm/overcommit_memoryThis file contains the kernel virtual memory accounting mo ...
- redis 在备份报错修改vm.overcommit_memory
/etc/sysctl.conf 添加 vm.overcommit_memory=1 刷新配置使之生效 sysctl vm.overcommit_memory=1 补充介绍: **如果内存情况比较紧张 ...
- linux 内存分配限制,overcommit_memory 2
诡异场景: 当你发现程序在申请大段内存的时候,发生申请失败. 这时候你通过查看free -g发现free下的内存还有大量可以使用的内存. 然后你再继续查看ulimit -a的时候,却发现max mem ...
最新文章
- [机器学习]超参数优化---贝叶斯优化(Bayesian Optimization) 理解
- 为什么Android Geeks购买Nexus设备
- 工业交换机与普通商用交换机的对比详解
- go分析和kegg分析_干货预警:3分钟搞定GO/KEGG功能富集分析(2)
- angularjs input标签用一个日期插件后数据不能双向绑定了_微信如何定时发朋友圈?(最方便最好用的办法!)...
- Android系统(76)---ART和Dalvik区别
- Docker学习总结(11)——八个Docker的真实应用场景
- llvm vs gcc 我被雷到了, 速度相差300多倍,你还用GCC吗!【转】
- php中mysql数据库集群,MySQL集群
- php表单提交的时候验证失败,解决有时首页表单提交“安全验证失败,请刷新页面后重新提交!”问题...
- 【2020春招记录】 吉比特游戏研发笔试
- Android学习笔记--Notification(通知)
- 一文读懂自然语言处理NLP
- Windows的权限(用户、组和访问控制)
- 【JavaWeb】火车票管理系统 (三)用户登录-03
- 2021 第十二届蓝桥杯 Java 省赛 B 组(第一场)真题解析
- 什么是WordPress插件?
- Quectel EC600N-CN 中尺寸物联网首选LTE Cat 1模块[移远通信]
- Mac系统环境变量配置和说明【实用版】
- 全球与中国扩管器驱动市场深度研究分析报告
热门文章
- python-pip安装及错误合集
- 王者荣耀各服务器位置,王者荣耀全国排行功能新上线,位置战力系统介绍[多图]...
- [转]关于如何保护眼睛,提高视力,防止近视?
- common-lang
- Javascript元素相关
- 小米手环是如何打动用户的?
- 荣耀linux版笔记本换硬盘,存储不够?小白首次拆机,荣耀MagicBook Pro升级硬盘记...
- Unity Build IOS包
- Css的基本学习 及 fireworks
- 大量电气自动化专业的Flash动画教程开始上架,你期待吗?