请教 Java OOM 及 JVM 相关的问题

67 天前
 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 大佬们给点建议,救救本菜,谢谢大家!

2779 次点击
所在节点    程序员
43 条回复
superhot
67 天前
@ZZ74
@silencegg

请问是通过什么判断的堆外内存不够的? >99% committed ?`mmap`?

@zhouhu

非常感谢,解释得很详细了,但自己太菜了术语太多有点看不懂,想确认一下:

> 此时 cs eden 区: 122 ,survivor cs: 18 ,JVM 完全可以进行垃圾收集。
> 从统计 E|cs: 122 + s|cs: 18 = 140 来说,当内存不足时,JVM 完全时可以进行 GC 的

也就是说,还存在 Young Generation 的话,就意味着还有可以 GC 的空间,而不需要申请新的内存,但因为还没达到 `-Xms` 设置的上限,所以为了性能 JVM 没选择 GC ,而是直接继续申请分配内存了,是这样理解吗?

另外注意到

```
MaxMetaspaceSize: unlimited
CompressedClassSpaceSize: 1.00 GB
Initial GC threshold: 20.80 MB
Current GC threshold: 136.30 MB
```

单 `CompressedClassSpaceSize` 就有 1G ,加上 `-Xmx2847m`,剩下的内存肯定不够给其他进程分配的,但因为未设置 `-Xms`,所以最开始 JVM 给 Heap 申请的大小没那么多,但随着程序运行,JVM 想要申请更多内存时,算上已经被用掉的堆外内存及其他进程占用的内存后,剩余可用内存不够分配,所以导致 JVM 发生 OOM (但其实),是这样吗?

把 JVM 参数设为

```
-Xms2560m -Xmx2560m -XX:MaxMetaspaceSize=256m -XX:ReservedCodeCacheSize=240m
```

是否可行?
zhouhu
67 天前
前面老哥们都说得很好。

物理内存不变的情况下,把 java 内存减少到 1.5G-2G 范围内应该是可行的。元空间的话也设置最大最小一样的吧

当年轻代耗尽时候会进行 Young GC 。

CompressedClassSpaceSize: 1.00 GB 这个参数是当前默认设置吧?
superhot
66 天前
感谢楼上各位老哥,先临时把 Heap 调低了一点,暂时没出什么问题,跟组长汇报了一下,之后考虑加上 Heap Dump 再观察一段时间。

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

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

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

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

© 2021 V2EX