如何快速分析Java OOM文件

文摘   职场   2024-06-13 10:00   江苏  
  1. 思考

    作为一个合格开发,怎么样才算见过“世面”——遇到多少异常才能在按键盘时就有意识避坑,解决多少问题才算大佬


  2. 前置

    上面的问题可以思考,但遇到问题时能想到解决办法也算一种成长!这里(https://www.51cto.com/article/764731.html)有约60个异常,感兴趣的可以CV一下,看看自己碰到过哪些?这篇只单拎一个OOM出来进行分析,毕竟这玩意儿一旦出现就意味着应用危险了。


    在启动脚本中可以增加相应的参数当发生OOM时dump出文件到指定目录,大致如下:

    -XX:HeapDumpPath=/data/logs/xxx/20231127_084922.hprof -XX:+UseG1GC -Xms8G -Xmx8G -Xss256k -Xloggc:/data/logs/xxx/gc.log -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError



    生成的文件一个特点——,如果技术同学从服务器上去下载文件下来,再用软件去分析,必然会浪费时间,还有一个问题就是:开发同学的机器不一定能把这么大的文件能成功读出来:

    一般线上的机器配置比开发机好,但线上那么多实例,也不能每个机器都装一个分析软件吧。所以可以找一台机器专门用来分析OOM,在上面装一个分析软件就好了。


  3. 流程

    先让运维同学参照:https://eclipse.dev/mat/downloads.php 这个地址安装软件。然后开发同学参照:https://juejin.cn/post/7014277586729566216 这个说明去使用就行。我们当前大概这样弄

    a. 进docker容器,找到dump文件

    docker exec -it ${docker_id or server_name} bash

    b. scp文件到安装分析软件的机器

    /**把本地文件拷贝到目标机器*/scp -r /data/logs/xxx/xxx.hprof root@${ip}:/data/memory_analysis/${dir}/xxx.suffix/**如果docker下没有scp需要先安装*/apt-get updateapt-get install openssh-client/**多学一个,把远程文件拷贝到本地目录*/scp -r root@${ip}:/data/memory_analysis/${dir}/xxx.suffix /xxx/xxx.suffix

    c. 找到mat的安装目录,执行命令

    ParseHeapDump.sh /data/memory_analysis/${dir}/xxx.hprof org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components/**如果dump文件没有,应用还可以响应*/jmap -dump:live,format=b,file=/logs/heapDump pid /**如果应用无法响应可以强行杀取heapdump*/jmap -F -dump:format=b,file=/logs/heapDump pid

    等待上面执行完成,去下载3个zip文件,解压后里面有一个index.html文件可以用浏览器打开:



    这样你就可以看到那个类的多少行占用空间大,常来说不出意外的话,开发沿着这里排查定位,是可以解决问题的,出意外就当我没说

  4. 快捷键

    上面的流程相对于拉到本地是快了不少,但有的时候OOM可以先在线上执行命令行:

    jmap -histo:live pid | more,如下图:

    分析:生成结果以bytes降序展示当前JVM堆上各对象占用资源大小的统计,有点类似栈。上面可以看到11行是DB操作,9行是一个对象,7行用了一个hutool工具来转,因为是做地图相关的业务,有的属性是geometry(point、polyline、polygon),为了方便在地理属性的列上使用一些聚合函数,所以我们有的服务用的DB是postgre整理一下就是:应用执行一次查询返回了一个对象,对象中有一个属性是geometry,又因为这个属性是一个multi_polygon的geometry,由几十万个point构成,要对这个属性类型进行转换,采用了hutools,导致把每一个coordinates(lng,lat)投射成Java的ArrayList对象时触发了OOM

    至此,问题被成功定位,这种方法比上面分析dump文件快得多。如有需要的同学,下次可以试试看


    P.S:众所周知,db的数据类型和应用的数据类型可以相互转,如果想知道geometry怎么转成Java对应的类型或者对postgre感兴趣的转身去看看《postgre的常用SQL操作


    关于jmap返回的jvm信息,准备再写一篇和prometheus(普罗米修斯集成),把数据通过Grafana展示出来……


    jdk常用的命令行学习参考:

    https://blog.csdn.net/syq8023/article/details/128972488


    有问题欢迎指出,听说吐槽与关注更配哦!!!


    不积跬步,无以至千里;

    不积小流,无以成江海。

    ——荀子《劝学》

晚霞程序员
一位需要不断学习的30+程序员……