jiobanma
V2EX  ›  Java

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

  •  
  •   jiobanma ·
    banmajio · Jul 23, 2022 · 5278 views
    This topic created in 1565 days ago, the information mentioned may be changed or developed.

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

    1. 报错信息

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

    2. 排查过程

    2.1 JVM 参数

    JVM 参数

    2.2 分析 dump 文件

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

    3. 其他

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

    1. 目前准备先把数据库里的重复的 url 干掉,但是应该解决不了实际问题,最大的几个对象加起来也就不到 100m 。
    2. 估计是哪里的接口或者操作触发了大批量的查询,导致数据都压到了内存中。先排查下代码,看看哪里有批量查询的地方,然后加一些范围条件。
    Supplement 1  ·  Jul 23, 2022
    ![在这里插入图片描述]( https://gitee.com/banmajio/my-picgo/raw/master/img/28A82E22D670D70B0ABF999583E9D0B7.png)

    补充一张 MAT 的 dump 截图。查过代码了,应该没有报表类的接口大批量数据的查询,不知道是不是连接池的问题
    26 replies  •  2022-07-26 10:10:31 +08:00
    jiobanma
    jiobanma
    OP
    Jul 23, 2022
    1
    大佬们可以给点指导建议,感谢。
    xiangxiangxiang
    xiangxiangxiang
    Jul 23, 2022
    2
    代码上传到 github 让大伙帮忙看看 🐶
    xiangxiangxiang
    xiangxiangxiang
    Jul 23, 2022❤️1
    3
    盲猜这个大对象是不是一个多层嵌套 map 或者说是树型结构(类似于文件目录+文件或者一颗特别大的类目树带类目下的商品详情这种场景),然后代码里有的地方不合理的 toJSON 打印日志,导致 oom 了?
    chendy
    chendy
    Jul 23, 2022
    4
    用 eclipse mat 分析一下试试?
    找内存占用大的线程,看看里面在执行什么逻辑
    jiobanma
    jiobanma
    OP
    Jul 23, 2022
    5
    @xiangxiangxiang 哈哈哈 上传 github 怕不是要和凡凡做室友了(dog 。 这个大对象是一些业务数据,之前的老代码把很多业务数据拼装成了一个 json 字段存到了数据库里。 有异常的几个对象的 json 里面充斥着大量重复的 url(应该是前端或者后端循环拼接 url 的时候死循环了)。 我只是不知道自己现在的排查方式对不对,是不是应该从这个角度分析。

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

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

    还有在打日志的时候,是否也有拼接现象 ?
    从这些方面看一看
    xuyang2
    xuyang2
    Jul 25, 2022
    19
    找找是不是有循环体里面 string += 的操作?
    jiobanma
    jiobanma
    OP
    Jul 25, 2022
    20
    @xuyang2
    @Nnq
    @goldenAndGreen
    @RuralHunter
    @dqzcwxb
    @luozic
    @manecocomph
    已解决,MAT 分析爆出的那个异常接口,controller 没有做参数校验,导致 sql 查了全表的数据,本来只是查一条数据的,把内存压满了,但是 sql 还没执行结束,导致一直 gc ,但是没法释放空间。
    e7
    e7
    Jul 25, 2022
    21
    @jiobanma limit 兜底是个好习惯
    luozic
    luozic
    Jul 25, 2022
    22
    定期扫 db 打性能分析日志,做优化。
    zhangyaxiao072
    zhangyaxiao072
    Jul 25, 2022
    23
    可能是哪里的代码又问题;下次溢出可以多抓几次线程,jstack ,仔细看看里面的信息
    mitsuizzz
    mitsuizzz
    Jul 25, 2022
    24
    @jiobanma 数据库层面有慢 SQL 监控的话,应该早就可以发现原因了。
    jiobanma
    jiobanma
    OP
    Jul 25, 2022
    25
    @e7 是呀 以后要注意了
    @luozic
    @mitsuizzz
    慢 sql 有监控的,只是项目太忙,一直没时间优化。而且很多都是老项目里的了,业务比较复杂,老员工都走的差不多了,不出大问题其他人不太敢动代码
    NeoZephyr
    NeoZephyr
    Jul 26, 2022
    26
    @manecocomph 继续泄露看到的也是 char[] bytes[] 大头啊
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2603 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 103ms · UTC 15:10 · PVG 23:10 · LAX 07:10 · JFK 10:10
    ♥ Do have faith in what you're doing.