线上 JVM 内存溢出, OOM 问题排查求指点。

2022-07-23 10:26:03 +08:00
 jiobanma

如题,线上有个服务跑着跑着就会 OOM ,导致所有请求失败,内存无法回收。

1. 报错信息

java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to /xxx/xxx/bootstrap/java_pid39726.hprof ...

2. 排查过程

2.1 JVM 参数

2.2 分析 dump 文件

用 VisualVM 分析 dump 文件发现,有个大对象占用了 33%的内存,如图①,查看该对象,发现里面大概有 200w 个对象,有一部分是空的,最大的几个对象就是顶部的那四五个。这些对象是一个 JSON 字符串,最上面几个大对象排查发现其中的 url 部分有大量重复,可能是前端提交数据或者后端处理 url 拼接的时候循环有问题,导致有大量重复的 url 使得其中这个对象特别的大。排查数据库,length 这个字段,最大的几个分别占用 9469799 ,4764368 ,4725799 ,4571257 。

3. 其他

JVM 调优经验较少,不知道是不是这么个排查流程,也不知道排查的点对不对。希望有经验的大佬给点指导。 补充几点:

  1. 目前准备先把数据库里的重复的 url 干掉,但是应该解决不了实际问题,最大的几个对象加起来也就不到 100m 。
  2. 估计是哪里的接口或者操作触发了大批量的查询,导致数据都压到了内存中。先排查下代码,看看哪里有批量查询的地方,然后加一些范围条件。
3468 次点击
所在节点    Java
26 条回复
jiobanma
2022-07-23 10:26:34 +08:00
大佬们可以给点指导建议,感谢。
xiangxiangxiang
2022-07-23 10:29:37 +08:00
代码上传到 github 让大伙帮忙看看 🐶
xiangxiangxiang
2022-07-23 10:31:53 +08:00
盲猜这个大对象是不是一个多层嵌套 map 或者说是树型结构(类似于文件目录+文件或者一颗特别大的类目树带类目下的商品详情这种场景),然后代码里有的地方不合理的 toJSON 打印日志,导致 oom 了?
chendy
2022-07-23 10:33:38 +08:00
用 eclipse mat 分析一下试试?
找内存占用大的线程,看看里面在执行什么逻辑
jiobanma
2022-07-23 10:50:04 +08:00
@xiangxiangxiang 哈哈哈 上传 github 怕不是要和凡凡做室友了(dog 。 这个大对象是一些业务数据,之前的老代码把很多业务数据拼装成了一个 json 字段存到了数据库里。 有异常的几个对象的 json 里面充斥着大量重复的 url(应该是前端或者后端循环拼接 url 的时候死循环了)。 我只是不知道自己现在的排查方式对不对,是不是应该从这个角度分析。

@chendy mac 装 mat 有点不太好装,jprofile 我有点不太会用。
tonymua
2022-07-23 11:10:58 +08:00
我们之前 Prometheus 监控项的时候 tag 对应的 List 里面元素顺序不一样 有过类似的情况
chendy
2022-07-23 11:15:54 +08:00
@jiobanma 哈哈确实,手持 m1 之前装 mat 费了不少劲,后来都借同事电脑跑
不过 mat 确实是最好使的工具了
micean
2022-07-23 11:19:08 +08:00
一般先考虑有没有文件处理业务,那种加载 excel 、csv 之类的
manecocomph
2022-07-23 11:28:27 +08:00
如果你觉得现在占 30%多的对象不够找出内存泄漏的真正源头, 我们一般把 heap 增大, 然后让它继续泄漏. 当你给它 8G heap 的时候, 还是 OOM, 还是占满, 然后去对比查看内存里的大对象, 就很快找到泄漏点了.
manecocomph
2022-07-23 11:34:33 +08:00
另外你标出来的 char[], byte[] 都很难找出来, 几乎所有的正常 Java 对象, 占大头的都是 char[], byte[] 等. 重点关注业务对象.
jiobanma
2022-07-23 11:46:03 +08:00
@manecocomph 我们的这个 char[] byte[]就是业务的大 json 字段,这里面全是这个 json
luozic
2022-07-23 11:48:35 +08:00
@jiobanma 排查代码里面搞点代码标记。 或者用 jmc 定位。
manecocomph
2022-07-23 11:49:51 +08:00
@jiobanma 同意, 绝大部分 Java 应用里面占 heap 的都是 char[], byte[]. 这些 json 被那些业务对象引用, 查查那些业务对象多不多. 推荐暂时增加 heap 让他尽情泄漏, 找出泄漏源.
luozic
2022-07-23 12:00:37 +08:00
https://www.jianshu.com/p/9baea772cb21 随便搜搜 ,这个介绍挺详细的
dqzcwxb
2022-07-23 12:44:58 +08:00
前几天处理过差不多的问题,用 caffeine 做本机缓存解决了当然前提是数据更新频率低以及能够接受一定延迟
RuralHunter
2022-07-23 20:46:01 +08:00
找你们自己域名内的类,看看内存和数量不正常的。基础库的类一般看不出什么花头。
goldenAndGreen
2022-07-23 23:47:53 +08:00
没配垃圾回收器吗,oom 之前有垃圾回收监测吗?可以确定是哪个区域吗?
如果是 G1 和 ZGC 可能更麻烦...
Nnq
2022-07-25 00:22:17 +08:00
你这个单纯拿出来一个截图很难说明问题, 分析 oom 也不是一下就能准确定位的

首先看看你所谓的占内存比较大的个体,看看为什么没有释放,是业务需求还是技术层面太多的字符串拼接之类的

还有在打日志的时候,是否也有拼接现象 ?
从这些方面看一看
xuyang2
2022-07-25 09:22:19 +08:00
找找是不是有循环体里面 string += 的操作?
jiobanma
2022-07-25 10:16:26 +08:00
@xuyang2
@Nnq
@goldenAndGreen
@RuralHunter
@dqzcwxb
@luozic
@manecocomph
已解决,MAT 分析爆出的那个异常接口,controller 没有做参数校验,导致 sql 查了全表的数据,本来只是查一条数据的,把内存压满了,但是 sql 还没执行结束,导致一直 gc ,但是没法释放空间。

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

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

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

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

© 2021 V2EX