背景

AWS EC2 t3.medium 实例,Amazon Linux 2 系统,4GB 内存。
Java 启动时 Heap 的配置为 -Xmx2847m,大概是给其他服务留 1G 左右内存,其余全部分配给 JVM 。
结合日志和后台监控发现频繁出现 OOM 导致 Tomcat 重启的问题。

问题

现在每个实例的平均内存使用率在 93% 左右,此现象是否正常?
保持当前 EC2 实例配置不变的情况下,给 JVM Heap 分配多大内存比较合适?有什么可以拿来当作判断的依据吗?
除了 Heap 之外,JVM 还有 Metaspace 、CodeCache 、DirectByteBuffers 等等,这些 Heap 之外的部分可能吃掉多少内存?有什么可以拿来当作判断的依据吗?
如何分析 OOM 可能的情况?/usr/share/tomcat 目录下有个 hs_err_pid 前缀的日志文件,似乎在 OOM 时会输出相关错误信息,但根本看不懂……

一年后端经验的 CRUD Boy 没系统学过 Java ,不了解 JVM ,突然让去解决 OOM 的问题,实在懵逼,不知从何下手,请各位 Java 大佬们给点建议,救救本菜,谢谢大家!

使用的是 Java 11,hs_err_pid 的内容在这里

堆内内存的话, dump 一份内存下来看占用内存的都是什么东西.

可以用 JVM 参数 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/heapdump 导出 OOM 时的 heap dump ,然后用工具分析,或者直接在应用程序运行的时候使用 jmap 导出当前对象分布的情况进行分析,推荐用这个: arthas.aliyun.com/doc/

什么版本的 Java ?如果版本高只想解决问题,那先:-XX:+UnlockExperimentalVMOptions-XX:+UseShenandoahGC-XX:ShenandoahGCHeuristics=compact

把这个 hs_err_pid 日志发出来,我最近也遇到 OOM 了,能帮忙排查下。可以看我最近发的一个帖子。

升级 ec2 ,给 8G 内存

springboot 的话加上 actuator, 配合 prometheus, grafana 看看 jvm 相关的使用情况; 90%的占用肯定不正常了, 相当于比较吃紧了, 如果来点压力就挂了, 再留一点内存给系统, 否则内存满了直接会被系统 kill

现在每个实例的平均内存使用率在 93% 左右,此现象是否正常? 正常。参考这个帖子 www.hesudu.com/t/1078482?p=1#reply22 贴出 hs_err_pid 内容。贴给 AI 都会给你分析。

jvm dump 分析网站,我自己懒得跑 MAT 的时候就用这个👻 heaphero.io/heap-index.jsp#header

例如代码里把 1G 文件全部一次性读入内存,先分析代码的原因。

给太高了吧。

除了堆内存还有堆外内存。

Java11 ,应该不算很高 链接贴在附言里了,函数名修改过,先谢过老哥,我去帖子学习下 只有升配置加内存这一条路了吗。。7 80 个实例,有点顶不住 ; w ; 问过 copilot ,没什么干货 我也有点怀疑这个 感谢提供思路,只是听过名词,对这些还没什么清晰的认识,我再研究研究

-Xmx 调小一点试试,比如 2000m总内存只有 4G ,设置-Xmx2847m 一定会 OOM

「结合日志和后台监控发现频繁出现 OOM 导致 Tomcat 重启的问题。」贴一下后台异常重启的日志呢。正常来说一个系统平稳运行是不应该 OOM 的。即使你的堆内存比较小,但是只要系统使用了内存之后正常释放,也是可以通过垃圾回收释放这些内存的。就是可能垃圾回收的频率比较高。如果频繁 OOM 的话,两种情况,一种是正常情况,处理请求的过程中,需要大量的内存,但是所有可回收的都已经回收了,还是不够。另一种就是代码写的有问题,该回收的没回收。堆内存配置看着比较合理,正常来说留一个 G ,一部分操作系统需要,一部分 JVM 的一些其他机制也需要堆外内存。比如线程堆栈。

看着楼主的意思就是 JVM 内部的 OOM 吧。老哥说的这种情况是堆外内存留少了,然后系统把 JVM 进程给干了。

在 Tomcat 的 Catalina 日志里看到的内容,正在连续处理请求的时候,每条日志的时间间隔小于 1s ,但明显该次请求还没处理完毕,上一条还是普通异常处理部分的日志,接下来就变成了类似 Tomcat startup 之类的信息,跟上一条隔了大概 30s ~ 70s 左右,以此来判断是重启过了。不过你说的这点确实需要再确认一下,这个重启到底跟 OOM 有没有关系。

/proc/meminfo:MemTotal: 3964656 kBMemFree: 114400 kBMemAvailable: 3092 kB他这很明显就是被 OOM killer 杀掉了。Java 8 之后若没设置 MaxDirectMemorySize ,默认跟 Xmx 是 1:1 的,OP 的机器 Xmx 超过 2g 有较大几率 OOM 。

请问这种情况下,怎样分配内存比较合理呢?我目前的想法也是先减少 Heap 大小试试看,但不知道靠什么来判断 -Xmx 的值设为多少比较合适。跟组长提方案的时候得拿证据……头疼。

你们业务量很大?最好 xmx 和 xms 设置为一样的 。一般的业务 1G 就好了。Xmx2847m 为什么是 2847 啊,虽然 G1 会自动对齐。

需要结合 GC 日志来分析,降低 Xmx 会提高 GC 频率,降低系统吞吐并增加系统延迟。调低 Xmx 后如果性能不达标,一般尝试调整参数优化 GC ,升级 JVM 版本可能也有些帮助。Tomcat 本身也有一些参数可以调整。如果这些都解决不了问题,那只能扩容或者优化代码了。

我猜你虽然设置了最大 Xmx2847m ,但是 JVM 启动的时候并没有申请那么多,当 运行一段时间后 JVM 再去申请内存,操作系统已经没有足够的内存了。所以设置 Xmx2048m Xms2048m通过查看不同 region 数量显示,如果是 2048M 还是有空余空间的。 Xmx2847mtotal 2847old: 1733free: 937HS: 18HC:19E|cs: 122s|cs: 18

我给出的方案是先设置。Xmx2048m Xms2048m 观察1. 打印详细 GC 日志 -Xlog:gc*=info ,更为详细的是 debug 和 trace2. -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/heapdump 分析内存镜像。3. 观察物理机内存使用情况。

没有参考标准,不知道如何判断业务规模,仅凭个人感觉不是很大,但现有架构已经撑不住了,虽然跑了 7 80 台 t3.medium 实例,还是经常超时死锁重启什么的…… 主要原因应该是代码质量差,之前的技术负责人跑路,祖传屎山摇摇欲坠。至于为什么是 2847……我也找不到人问 hhhh感谢提供思路,我明天再查查 Heap Dump ,印象里好像是有这么个东西的。