內存還有很多卻說內存不足,物理內存充足,但是為什么用代碼總申請不到內存呢?

 2023-10-22 阅读 27 评论 0

摘要:作者?|?牧原來源 |?程序猿石頭(ID:tangleithu)頭圖 |? CSDN?下載自東方IC本文作者:楊牧原(花名牧原),阿里云技術專家,多年操作系統和應用調試經驗,理論功底深厚,實踐經驗豐富。目前專注Linux性能調優

作者?|?牧原

來源 |?程序猿石頭(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:當前已經分配的內存大小;

cpu內存不足怎么辦。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的火焰已無法熄滅
點分享點點贊點在看

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/160562.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息