作者 | 牧原

来源 | 程序猿石头(ID:tangleithu)

头图 |  CSDN 下载自东方IC

本文作者:杨牧原(花名牧原),阿里云技术专家,多年操作系统和应用调试经验,理论功底深厚,实践经验丰富。目前专注Linux性能调优,容器集群和系统网络。

背景

某次遇到一个客户尝试用 Java (其实跟具体用什么语言没关系)申请使用 4G 的内存申请,机器(ECS)总内存是 8G,free 的内存也超过 4G,按道理是 OK 的,但总是直接 OOM。

于是便找上门来说,“你们这玩意有问题啊?”

内心 :“bug 是不可能有的,一定是你的打开姿势不对”,恩,不行,本着“客户第一”的原则,还是要来帮客户解锁姿势的。

本文就详细记录了这个 case 的排查过程。

具体过程

申请4g内存失败

如上图所示,记录显示为申请 4G 内存失败(4294967296 B / 1024 / 1024 = 4096 M)。

是否是 min_free_kbytes & nr_hugepage 配置错误?

  1. 第一反应是想起来之前的 vm.min_free_kbytes & nr_hugepage 导致的free大于available案例有关

memfree 统计的是所有内存的 free 内存,而 memavailable 统计的是可以拿来给程序用的内存,而客户设置了 vm.min_free_kbytes(2.5G),这个内存在 free 统计,但是不在 memavailable 统计,nr_hugepage 也会有这个问题。

二者的统计方式不一样, 具体参考 Documentation/filesystems/proc.txt

  • MemFree: The sum of LowFree+HighFree

  • MemAvailable: An estimate of how much memory is available for starting new applications, without swapping. Calculated from MemFree, SReclaimable, the size of the file LRU lists, and the low watermarks in each zone. The estimate takes into account that the system needs some page cache to function well, and that not all reclaimable slab will be reclaimable, due to items being in use. The impact of those factors will vary from system to system.

  1. 跟客户要 free -m && sysctl -p && /proc/meminfo 等信息分析问题。

  • HugePages_Total 为0,说明没有设置 nr_hugepage。

  • MemAvailable: 7418172 kB, 说明这么多内存可用。

# sysctl -pnet.ipv4.ip_forward = 0net.ipv4.conf.default.accept_source_route = 0kernel.sysrq = 1kernel.core_uses_pid = 1net.ipv4.tcp_syncookies = 1...net.ipv4.tcp_tw_recycle=1net.ipv4.tcp_max_syn_backlog=4096net.core.netdev_max_backlog=10000vm.overcommit_memory=2...
#cat /proc/meminfoMemTotal:        8009416 kBMemFree:         7347684 kBMemAvailable:    7418172 kBBuffers:           18924 kBCached:           262836 kBSwapCached:            0 kBActive:           315188 kBInactive:         222364 kBActive(anon):     256120 kBInactive(anon):      552 kBActive(file):      59068 kBInactive(file):   221812 kB....HugePages_Total:       0  HugePages_Free:        0HugePages_Rsvd:        0HugePages_Surp:        0Hugepagesize:       2048 kBDirectMap4k:      114560 kBDirectMap2M:     4079616 kBDirectMap1G:     6291456 kB

尝试重现

  1. 尝试自行测试使用java命令,去申请超出我的测试机物理内存,拿到报错。

实际上面的meminfo已经说明了问题,但是由于经验不足,一时没有看明白怎么回事。

下面测试证明正常申请内存不会有问题,超额的内存才会 OOM。

[root@test ~]# java -Xms4096M -versionopenjdk version "1.8.0_242"OpenJDK Runtime Environment (build 1.8.0_242-b08)OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)[root@test ~]# java -Xms5000M -versionOpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000687800000, 3495428096, 0) failed; error='Cannot allocate memory' (errno=12)......

系统信息如下:

---------------  S Y S T E M  ---------------
OS:CentOS Linux release 7.4.1708 (Core)
uname:Linux 3.10.0-693.2.2.el7.x86_64 #1 SMP Tue Sep 12 22:26:13 UTC 2017 x86_64
libc:glibc 2.17 NPTL 2.17
rlimit: STACK 8192k, CORE 0k, NPROC 15088, NOFILE 65535, AS infinity
load average:0.05 0.05 0.05
/proc/meminfo:
MemTotal:        3881692 kB
MemFree:         2567724 kB
MemAvailable:    2968640 kB
Buffers:           69016 kB
Cached:           536116 kB
SwapCached:            0 kB
Active:           355280 kB
Inactive:         326020 kB
...
VmallocTotal:   34359738367 kB
VmallocUsed:       14280 kB
VmallocChunk:   34359715580 kB
HardwareCorrupted:     0 kB
AnonHugePages:     30720 kB
HugePages_Total:     256
HugePages_Free:      256
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:       57216 kB
DirectMap2M:     3088384 kB
DirectMap1G:     3145728 kB
....
Memory: 4k page, physical 3881692k(2567600k free), swap 0k(0k free)
vm_info: OpenJDK 64-Bit Server VM (25.242-b08) for linux-amd64 JRE (1.8.0_242-b08), built on Jan 28 2020 14:28:22 by "mockbuild" with gcc 4.8.5 20150623 (Red Hat 4.8.5-39)
time: Thu Feb 20 15:13:30 2020
timezone: CST
elapsed time: 0 seconds (0d 0h 0m 0s)

重现失败,继续分析

  1. Java 测试证明正常申请内存不会有问题,超额的内存才会 OOM,那么为什么超额呢,视线回归到 sysctl -p 有所发现。

vm.overcommit_memory=2

关于 overcommit_memory 设置项:

overcommit_memory=0

默认设置,当应用进程尝试申请内存时,内核会做一个检测。内核将检查是否有足够的可用内存供应用进程使用;

如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。

举个例子,比如1G的机器,A进程已经使用了500M,当有另外进程尝试malloc 500M的内存时,内核就会进行check,发现超出剩余可用内存,就会提示失败。

overcommit_memory=1

对于内存的申请请求,内核不会做任何check,直到物理内存用完,触发 OOM 杀用户态进程。

同样是上面的例子,1G 的机器,A进程500M,B进程尝试 malloc 500M,会成功,但是一旦kernel发现内存使用率接近1个G(内核有策略),就触发OOM,杀掉一些用户态的进程(有策略的杀)。

overcommit_memory=2

当请求申请的内存 >= SWAP内存大小 + 物理内存 * N,则拒绝此次内存申请。解释下这个N:N是一个百分比,根据overcommit_ratio/100来确定,比如overcommit_ratio=50(我的测试机默认50%),那么N就是50%。vm.overcommit_ratio 只有当 vm.overcommit_memory = 2 的时候才会生效,内存可申请内存为 SWAP内存大小 + 物理内存 * overcommit_ratio/100。

看看上面日志的 overcommit 信息:

  • CommitLimit: 4004708 kB (小于客户申请的4096M)

  • Committed_AS: 2061568 kB

具体而言:

  • CommitLimit:最大能分配的内存(测试下来在vm.overcommit_memory=2时候生效),具体的值是:SWAP内存大小(ecs均未开启) + 物理内存 * overcommit_ratio / 100;

  • Committed_AS:当前已经分配的内存大小;

5,两相对照,说明客户设置的 vm.overcommit_memory在生效,建议改回 0 再试试。

  • 用 vm.overcommit_memory = 2 测试,分配内存失败;

[root@test ~]# grep -i commit /proc/meminfoCommitLimit:     1940844 kBCommitted_AS:     480352 kB# java -Xms2048M -version 失败了OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000080000000, 1431830528, 0) failed; error='Cannot allocate memory' (errno=12)## There is insufficient memory for the Java Runtime Environment to continue.# Native memory allocation (mmap) failed to map 1431830528 bytes for committing reserved memory.# An error report file with more information is saved as:# /root/hs_err_pid1267.log
  • 用如下配置,即可恢复:vm.overcommit_memory = 0, vm.overcommit_ratio = 50

#vm.overcommit_memory = 0#vm.overcommit_ratio = 50[root@test ~]# java -Xms2048M -versionopenjdk version "1.8.0_242"OpenJDK Runtime Environment (build 1.8.0_242-b08)OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)

最后

可以看出,这其实跟具体的编程语言没有关系,用 Java 申请不到,用 c++/c 也一样。一个容易忽略的小知识点,你 get 到了吗?

本文节选自《ECS运维指南之Linux系统诊断》,《ECS运维指南之Linux系统诊断》是牧原呕心沥血之作,不仅内容精益求精,代码的编排作者也花了不少心思。你可以直接登录阿里云开发者社区下载本书——《ECS运维指南之Linux系统诊断》。阿里云开发者社区有不少高质量技术文章,大家可以去观摩学习,有很多书籍都是可以直接免费下载的。

更多精彩推荐
☞信息技术产业的黄金十年?听听他怎么说
☞九问国产操作系统,九大掌门人万字回应!
☞突围 2020!程序员这样学 AI !☞一文读懂机器学习“数据中毒”☞深度揭秘:腾讯存储技术发展史
☞用0和1书写新金融体系,DeFi的火焰已无法熄灭
点分享点点赞点在看

物理内存充足,但是为什么用代码总申请不到内存呢?相关推荐

  1. 我开发的代码,如何申请版权_代码简介:我花了3个月时间申请开发人员职位。 这是我学到的。...

    我开发的代码,如何申请版权 Here are three stories we published this week that are worth your time: 这是我们本周发布的三个值得您 ...

  2. C/C++代码调试:快速定位内存的申请和释放的位置

    1.问题 如果大型项目中出现类似于*** glibc detected *** logcacheinit: double free or corruption (fasttop): 0x0000000 ...

  3. EV代码签名申请步骤

    一.EV代码签名申请前提 1.单位成立时间不低于:3个月 2.单位工商及企查查可查 3.单位经营正常 4.注册地址真实存在,禁止使用集中注册地址 5.企查查登记电话或邮箱,确定查询结果的电话可以接听, ...

  4. malloc一次性最大能申请多大内存空间

    受用户态内存地址空间的限制.64 位系统下分配几个 T 不成问题. 著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 作者:zz matrix 链接:http://www.zhi ...

  5. 64位系统下,一个32位的程序究竟可以申请到多少内存,4GB还是更多

    前言: cpu的位是指一次性可处理的数据量是多少,1字节=8位,32位处理器可以一次性处理4个字节的数据量,依次类推.32位操作系统针对的32位的CPU设计.64位操作系统针对的64位的CPU设计.操 ...

  6. 让Linux使用malloc申请更多的内存

    项目遇到一个问题,程序跑着跑着就会挂掉,从多方信息分析来看,发现在设备的linux系统中,一个进程申请的内存最大只能达到1GB,而设备所用的物理内存是2GB的.我们的程序有多个进程,但主进程只有一个, ...

  7. 64位系统下一个32位的程序究竟可以申请到多少内存?

    64位系统下一个32位的程序究竟可以申请到多少内存? cpu的位是指一次性可处理的数据量是多少,1字节=8位,32位处理器可以一次性处理4个字节的数据量,依次类推.32位操作系统针对的32位的CPU设 ...

  8. 64位系统下,一个32位的程序究竟可以申请到多少内存,4GB还是更多?

    前言: cpu的位是指一次性可处理的数据量是多少,1字节=8位,32位处理器可以一次性处理4个字节的数据量,依次类推.32位操作系统针对的32位的CPU设计.64位操作系统针对的64位的CPU设计.操 ...

  9. Win10系统VS2022的VC++一次最多可以申请多大内存

    在Win10操作系统中,使用Visual Studio的VC++验证,一次最多可以申请内存的上限是多少. 使用的是个人笔记本电脑,配置如下图所示.内存8G,操作系统是"Windows 10家 ...

最新文章

  1. MySQL 错误1418
  2. spring security3.x学习(12)_remember me
  3. [Hadoop]Hive-1.2.x安装配置+Mysql安装
  4. python哪一版好用-Python 可视化工具库哪款最好用?哪款最不好用?
  5. SpringBoot与Spring的对比
  6. 如何用Python画画
  7. 喜大普奔:Datawhale开源项目《李宏毅机器学习完整笔记》发布了!
  8. Java获取linux服务器cpu、内存、硬盘相关信息
  9. Tech·Ed 2006中国 实况报道
  10. stm32 SPI架构
  11. 修改Maven默认编译级别
  12. no talloc stackframe at ../source3/param/loadparm.c:4864, leaking memory
  13. ctf赛题上传一个php木马,文件上传的ctf_web题目【伪协议】
  14. 《Adobe Illustrator CS6中文版经典教程(彩色版)》—第0课0.14节使用画笔工具
  15. More Accurate Question Answering on Freebase阅读笔记
  16. 羡慕寻龙分金闯古墓?心动何不行动
  17. 物流中的独立节点路由试算
  18. Android--CardView详解
  19. 自建ES通过OSS快照迁移至阿里云ES
  20. 启元世界内推招聘(对标阿里P6-P7)

热门文章

  1. 【软件测试从入门到放弃】熟悉阶段:软件测试流程
  2. 【Linux 驱动】第十章 中断处理
  3. SUSE12SP3-Mycat(4)rule.xml配置详解
  4. WPF 自定义BarChartControl(可左右滑动的柱状图)
  5. 史上最简单MySQL教程详解(基础篇)之SQL语句以及预留关键字介绍
  6. Linux服务器开发初步
  7. 怎么升级iOS10教程
  8. 【转】软件开发常用术语
  9. 求职历程之-----我的求职信
  10. 伪分布式kafka安装与验证