V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
jiobanma
V2EX  ›  Java

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

  •  
  •   jiobanma ·
    banmajio · 2022-07-23 10:26:03 +08:00 · 3419 次点击
    这是一个创建于 614 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,线上有个服务跑着跑着就会 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. 估计是哪里的接口或者操作触发了大批量的查询,导致数据都压到了内存中。先排查下代码,看看哪里有批量查询的地方,然后加一些范围条件。
    第 1 条附言  ·  2022-07-23 14:22:40 +08:00
    ![在这里插入图片描述]( https://gitee.com/banmajio/my-picgo/raw/master/img/28A82E22D670D70B0ABF999583E9D0B7.png)

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

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

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

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