请教 Java OOM 及 JVM 相关的问题

63 天前
 superhot

背景

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

问题

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

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

2764 次点击
所在节点    程序员
43 条回复
BBCCBB
63 天前
堆内内存的话, dump 一份内存下来看占用内存的都是什么东西.
2Nfree
63 天前
可以用 JVM 参数 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/heapdump 导出 OOM 时的 heap dump ,然后用工具分析,或者直接在应用程序运行的时候使用 jmap 导出当前对象分布的情况进行分析,推荐用这个: https://arthas.aliyun.com/doc/
INCerry
63 天前
什么版本的 Java ?如果版本高只想解决问题,那先:

-XX:+UnlockExperimentalVMOptions
-XX:+UseShenandoahGC
-XX:ShenandoahGCHeuristics=compact
Geekerstar
63 天前
把这个 hs_err_pid 日志发出来,我最近也遇到 OOM 了,能帮忙排查下。可以看我最近发的一个帖子。
defunct9
63 天前
升级 ec2 ,给 8G 内存
wenning
63 天前
springboot 的话加上 actuator, 配合 prometheus, grafana 看看 jvm 相关的使用情况; 90%的占用肯定不正常了, 相当于比较吃紧了, 如果来点压力就挂了, 再留一点内存给系统, 否则内存满了直接会被系统 kill
ZZ74
63 天前
现在每个实例的平均内存使用率在 93% 左右,此现象是否正常? 正常。
参考这个帖子 https://www.v2ex.com/t/1078482?p=1#reply22 贴出 hs_err_pid 内容。贴给 AI 都会给你分析。
xiwolaisi
63 天前
jvm dump 分析网站,我自己懒得跑 MAT 的时候就用这个👻
https://heaphero.io/heap-index.jsp#header
jorneyr
63 天前
例如代码里把 1G 文件全部一次性读入内存,先分析代码的原因。
paranoiagu
63 天前
给太高了吧。
paranoiagu
63 天前
除了堆内存还有堆外内存。
superhot
63 天前
@INCerry Java11 ,应该不算很高

@Geekerstar 链接贴在附言里了,函数名修改过,先谢过老哥,我去帖子学习下

@defunct9 只有升配置加内存这一条路了吗。。7 80 个实例,有点顶不住 ; w ;

@ZZ74 问过 copilot ,没什么干货

@wenning 我也有点怀疑这个


@xiwolaisi
@BBCCBB
@2Nfree
感谢提供思路,只是听过名词,对这些还没什么清晰的认识,我再研究研究
sagaxu
63 天前
-Xmx 调小一点试试,比如 2000m

总内存只有 4G ,设置-Xmx2847m 一定会 OOM
yuemingming
63 天前
「结合日志和后台监控发现频繁出现 OOM 导致 Tomcat 重启的问题。」
贴一下后台异常重启的日志呢。
正常来说一个系统平稳运行是不应该 OOM 的。即使你的堆内存比较小,但是只要系统使用了内存之后正常释放,也是可以通过垃圾回收释放这些内存的。就是可能垃圾回收的频率比较高。
如果频繁 OOM 的话,两种情况,一种是正常情况,处理请求的过程中,需要大量的内存,但是所有可回收的都已经回收了,还是不够。另一种就是代码写的有问题,该回收的没回收。
堆内存配置看着比较合理,正常来说留一个 G ,一部分操作系统需要,一部分 JVM 的一些其他机制也需要堆外内存。比如线程堆栈。
yuemingming
63 天前
@sagaxu 看着楼主的意思就是 JVM 内部的 OOM 吧。老哥说的这种情况是堆外内存留少了,然后系统把 JVM 进程给干了。
superhot
63 天前
@yuemingming 在 Tomcat 的 Catalina 日志里看到的内容,正在连续处理请求的时候,每条日志的时间间隔小于 1s ,但明显该次请求还没处理完毕,上一条还是普通异常处理部分的日志,接下来就变成了类似 Tomcat startup 之类的信息,跟上一条隔了大概 30s ~ 70s 左右,以此来判断是重启过了。不过你说的这点确实需要再确认一下,这个重启到底跟 OOM 有没有关系。
sagaxu
63 天前
@yuemingming

/proc/meminfo:
MemTotal: 3964656 kB
MemFree: 114400 kB
MemAvailable: 3092 kB

他这很明显就是被 OOM killer 杀掉了。

Java 8 之后若没设置 MaxDirectMemorySize ,默认跟 Xmx 是 1:1 的,OP 的机器 Xmx 超过 2g 有较大几率 OOM 。
superhot
63 天前
@sagaxu 请问这种情况下,怎样分配内存比较合理呢?我目前的想法也是先减少 Heap 大小试试看,但不知道靠什么来判断 `-Xmx` 的值设为多少比较合适。跟组长提方案的时候得拿证据……头疼。
zhouhu
63 天前
@superhot 你们业务量很大?最好 xmx 和 xms 设置为一样的 。一般的业务 1G 就好了。

Xmx2847m 为什么是 2847 啊,虽然 G1 会自动对齐。
sagaxu
62 天前
@superhot 需要结合 GC 日志来分析,降低 Xmx 会提高 GC 频率,降低系统吞吐并增加系统延迟。调低 Xmx 后如果性能不达标,一般尝试调整参数优化 GC ,升级 JVM 版本可能也有些帮助。Tomcat 本身也有一些参数可以调整。如果这些都解决不了问题,那只能扩容或者优化代码了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1081255

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX