思考
作为一个合格开发,怎么样才算见过“世面”——遇到多少异常才能在按键盘时就有意识避坑,解决多少问题才算大佬
前置
上面的问题可以思考,但遇到问题时能想到解决办法也算一种成长!这里(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,在上面装一个分析软件就好了。
流程
先让运维同学参照: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 update
apt-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文件可以用浏览器打开:
这样你就可以看到那个类的多少行占用空间大,通常来说不出意外的话,开发沿着这里排查定位,是可以解决问题的,出意外就当我没说
快捷键
上面的流程相对于拉到本地是快了不少,但有的时候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
有问题欢迎指出,听说吐槽与关注更配哦!!!
不积跬步,无以至千里;
不积小流,无以成江海。
——荀子《劝学》