内存还有几十G,为何jvm会oom crash

内存还有几十G,为何jvm会oom crash

立秋已过,但成都仍是燥热难耐。现在已经晚上九点,经过一天暴晒的房子开始源源不断的释放热量,朝我奔袭而来,无处躲藏。不一会就已经满头大汗,在地心引力的作用下,汗珠从锁骨处越过高山,汇聚后顺着腹部深邃的沟壑往下流淌,又不断往两边分叉,肆无忌惮的在我身上写着“丰”字。我的思绪又开始天马行空的晃荡了,一会想着这个字是不是预示着汗水将带来丰收,转念又思考,为什么没有汗流成河这个成语呢。

突然一阵铃声响起,我心里一惊,通常这个时候来的电话都没啥好事,不是宕机了就是宕机了。我拿起手机一看,是鹏哥打过来的,他今年给我打了四次电话,都是紧急事件。一阵寒意袭上心来,挡住了这夜的热浪。

“喂,鹏哥,找我啥事?” 我故作镇定的问道。

“水哥,是这样,我们这有台服务器,还有50多G内存,但是一启 apache ftp server 就报内存不足,它这个应该设置多大内存呀?” 鹏哥略显拘谨,小心翼翼的问道。

这让我有点不解, apache ftp server 就直接运行启动脚本就行了,也不需要特意设置内存,而且 ftp server 本身也不怎么吃内存,怎么可能启动就报错,一定是现场又把啥给搞错了,这还是第一次有人问我 ftp 部署的事。虽有一丝丝不快,但以我对鹏哥的了解,他一定又是和现场折腾了半天,实在搞不定了才来找我的。

继续追问,也用处不大,于是说到:“鹏哥,你把日志发我,我看一下”。

问题排查

不一会,鹏哥发我发了 jvm crash 日志,日志显示:

# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 4294967296 bytes for committing reserved memory.
# Possible reasons:
#   The system is out of physical RAM or swap space
#   The process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap
...
# Java VM: Java HotSpot(TM) 64-Bit Server VM (18.0.1.1+2-6, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64)

jvm 在 mmap 申请内存时就报错了,申请大概4G 内存。free -m 看了一下,free 内存有40多 G ,available 内存还有50多 G ,申请4G 内存咋会直接 crash 呢。

日志中显示用的 jdk 版本是 18.0 ,这是一个值得关注的点,咱公司啥时候用这么新的 jdk 了, 我们用 apache ftp server 一般也是在 jdk 1.8 上运行,是不是它俩配合有啥问题。 于是让现场运行一下 java -version 再判断一下版本,结果现场说执行 java -version 就报错了,也是无法申请足够内存。

想不到运气这么好,直接把 ftp serverjdk 18 结合有问题这个可能性给排除了。 内存肯定是够的,但是 java -version 都会报内存不够,这是为什么呢。我闭上眼睛,清空杂念,在脑海中把各种信息与我掌握的知识做关联,试着找出下一步排查的方向。

“爸爸,你看我画的这幅画怎么样。” 一阵可爱而又刺耳的声音不断的传来,把我从沉思中拉回来。这小调皮蛋捣乱从来不分场合呀,她没看出来我正在思考问题吗。

“你走开,爸爸有事。” 我没好气的呵斥道,边说边往屋外走去,留下宝宝委屈的呆站在原地,眼中泛着泪花。我来不及多想,径直走到客厅,继续思考。

  • 内存肯定是够的
  • 和 apache ftp server 没什么关系。
  • 服务器上是不是装了其他耗资源的软件。
  • 是不是别的什么资源不够,比如文件句柄啥的,但是错误信息反馈的是内存不够。
  • 是不是服务器有什么特殊的内核参数配置。

于是又和鹏哥电话沟通,了解了一些情况

  • 这台服务器上还装着几个核心应用,还有多个数据库,包括一个 gp 库。 ftp 跟他们装一台机器上,我也是挺害怕的。
  • swap 分区是0,这台机器直接禁用了 swap ,全部用内存。问了一下现场为什么这么配,说是之前就这么配的,习惯了。
  • 之前 gp 库啥的也可能会出现无法分配内存,于是写了个脚本,定时清空缓存。 那看来问题一直是有的
  • 为什么装 jdk 18 , 因为之前老是内存不够,无法启动,于是下个 jdk 最新版试试。这个也吓了我一跳。
  • cat /proc/sys/vm/max_map_count 看了一下,配置很大,肯定用不完
  • 看了一下 overcommit_memoryovercommit_ratio 两个值
    • overcommit_memory 2
    • overcommit_ratio 95
    • 意思是不允许内存超配, 内存阈值是 95% ,也就是 128G * 95%

网上的很多案例都指向了 overcommit_memory 这个配置,于是双让现场运行了一下命令:

grep -i commit /proc/meminfo

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fp5bn37L-1661388713525)(https://bed.cdpt.pro/ibed/2022/08/16/FGFl8Nqts.png)]

CommitLimit 好理解,就是其内存阈值: 128G * overcommit_ratio (95%)
Committed_AS 代表啥呢? 在 https://www.kernel.org/doc/html/v4.19/vm/overcommit-accounting.html 这篇贴子上有一句话:
- The current overcommit limit and amount committed are viewable in /proc/meminfo as CommitLimit and Committed_AS respectively.

意思是 Committed_AS 代表的是已经 Committed 的内存,根据前面查到的值, Committed_ASCommitLimit 只差 1G 多了,随便干点啥都可能会报申请不到足够的内存了。

Committed 内存 跟 Used 内存又有什么联系和区别呢

进程在申请内存时,它可能申请了并且分配使用了,这就是 Used , 申请了但是还没用那就是 Committed 。 可以通过 overcommit_memory 参数来控制是否允许内存超配。

举个例子,航空公司售票:

  • 卖出去的票就是 Committed_AS
  • overcommit_memory 配置成 1,就允许超售,而且不设置阈值,你敢买它就敢卖。但是如果超了怎么办,一种是经济仓调成头等舱(类似于从内存换成 swap 分区);另一种就是拒绝登机(启动 oom killer 来杀进程),当然航空公司拒绝谁来登机肯定是有它的算法的,它不会随机来弄,只会挑软柿子捏, linux 也是这么干的,通过 badness 来选择软柿子。
  • 进程通常会多申请内存 ,如果航空公司不登机自动全额退费的话,肯定很多人是先买票,然后看有别的便宜的票就买。 如果 overcommit_memory 配置成 2, 不允许超配,那运行过程中出现 oom 的可能性就非常小了;但是完全不允许超配的话,会带来非常大的浪费,你会发现明明 free 内存还有一大半,但是就是不能给别人用。

结论

overcommit_memory 设置为 1 后,再运行 java -version 或者别的命令就不会报内存不够了,说明确实与此有关。

如果 overcommit_memory 设置为2(不允许超配),你就会发现即使还有大把内存,但是进程会报无法获取足够的内存。

那 jvm 的 Xms 和 Xmx 参数与 commit_memory 之间又有什么联系呢,我预想的是 Xms 代表 Used 内存,这个一定是被使用的内存, Xmx 代表 commit 的内存。试验之后,发现 Xmx 会占用一些 Commit 内存,但是没有分析出其比例关系。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OMNLC0uM-1661388713526)(https://bed.cdpt.pro/ibed/2022/08/16/FGIILzT3g.png)]

参考资料

  • https://redis.io/docs/getting-started/faq/#background-saving-fails-with-a-fork-error-under-linux-even-if-i-have-a-lot-of-free-ram redis官方对于 overcommit 的建议
  • https://www.kernel.org/doc/Documentation/vm/overcommit-accounting 官方对于 overcommit 的解释
  • https://superuser.com/questions/971967/why-is-my-committed-memory-so-much-higher-than-my-actual-ram-space
  • https://serverfault.com/questions/942173/is-committed-as-in-proc-meminfo-really-the-correct-number-for-allocated-virtual
  • https://lwn.net/Articles/28345/
  • https://stackoverflow.com/questions/41468670/difference-in-used-committed-and-max-heap-memory#:~:text=committed%3A%20amount%20of%20memory%20that,for%20the%20java%20process%20anyway.
  • https://jingchao.org.cn/2020/03/25/Linux%E4%B8%AD%E7%9A%84Committed_AS%E4%B8%8ECommitLimit.html
  • https://gpdream.github.io/2017/01/04/java/jvm%20oom%20beacuse%20of%20system%20vm%20config/ 飞雄转的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值