当前位置 博文首页 > 韩超的博客 (hanchao5272):记一次服务频繁崩溃的JVM调试过程

    韩超的博客 (hanchao5272):记一次服务频繁崩溃的JVM调试过程

    作者:[db:作者] 时间:2021-09-05 16:18

    问题简介

    • 项目P负责提供数据统计分析查询服务。
    • 项目P之前的运行比较稳定。
    • 项目P最近每天都会崩溃。

    解决历史

    • 对所涉及表进行分库分表:问题未解决。
    • 将log4j升级成log4j2,并采用异步日志机制:问题未解决。
    • 升级jdk版本:问题未解决。
    • 优化外部服务API访问方式为池技术:问题未解决。

    本次解决过程

    通过jps -v获取启动参数

    [root@11.11.11.11 services]# jps -v |grep -v Jps
    17 jar -Xmx8192m -Xms8192m -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -Xloggc:/home/services/serviceA/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
    

    可知:

    • 最大堆内存为8GB。
    • 垃圾回收器选用的G1。

    通过jcmd获取类实例直方图

    多次获取的类实例直方图都如下:

    [root@11.11.11.11 services]# jcmd 17 GC.class_histogram |head -n14
    17:
    
     num     #instances         #bytes  class name
    ----------------------------------------------
       1:         10474      238943216  [B
       2:        791538       18996912  java.lang.Long
       3:        113599       11892216  [C
       4:        187962        7518480  pers.hanchao.serviceA.vo.InfoNode$AreaNode
       5:        187962        6014784  pers.hanchao.serviceA.vo.InfoNode
       6:        187962        6014784  pers.hanchao.serviceA.vo.InfoNode$AgeNode
       7:        187962        6014784  pers.hanchao.serviceA.vo.InfoNode$TierNode
       8:         21172        5554168  [Ljava.lang.Object;
       9:        187962        4511088  pers.hanchao.serviceA.vo.InfoNode$DeviceNode
      10:        187962        4511088  pers.hanchao.serviceA.vo.InfoNode$GenderNode
    

    有一次特殊的类实例直方图如下:

     num     #instances         #bytes  class name
    ----------------------------------------------
       1:      72606461     4369167240  [C
       2:      72602667     1742464008  java.lang.String
       3:         24025      379820216  [Ljava.lang.Object;
       4:         65562      245431048  [B
       5:        868181       20836344  java.lang.Long
       6:        187962        7518480  pers.hanchao.serviceA.vo.InfoNode$AreaNode
       7:        187962        6014784  pers.hanchao.serviceA.vo.InfoNode
       8:        187962        6014784  pers.hanchao.serviceA.vo.InfoNode$AgeNode
       9:        187962        6014784  pers.hanchao.serviceA.vo.InfoNode$TierNode
      10:        187962        4511088  pers.hanchao.serviceA.vo.InfoNode$DeviceNode
    
    • 对比直方图,发现突增的char[]String类型占用了4369167240 + 1742464008bytes,大概6GB内存,将近最大内存的75%,可能就是造成JVM的原因。

    问题猜想

    根据上述突增的String实例情况,猜想可能产生问题的原因如下:

    • 猜想一:可能存在某个接口直接从数据库中读取大量(千万级?亿级?)数据至内存中。
    • 猜想二:可能存在某个接口读取中量(十万?上百万?)数据,然后进行空间复杂度很高(如n^2)的算法。
    • 猜想三:其他产生大量String实例的情况。

    问题确认

    经排查,确实存在一个接口会因为传参不当,导致查询全表,并将全表记录读取到内存中。

    问题解决

    修复接口,重新上线,问题解决。

    总结

    • 本次调优过程较为简单,并且比较幸运,恰巧碰到一次异常情况。
    • 遇到更为复杂的问题,可能就不是直接对运行中的JVM进行排查就能解决的,到时候,可要对下列文件进行更加深入的分析:
      • 因堆OOM产生的堆Dump文件(*.hprof)。
      • 垃圾回收日志(gc.log)。
    cs