JAVA 服务内存占用过高的一次排查过程

下面内容不用看了,非常建议使用阿里开源的artHas工具,使用非常方便,排查内存,bug非常容易

 

 

1. 缘由

一台线上机器内存耗尽,OOM 导致服务注册的 Mesh 客户端被干掉了,大量服务调用异常。运维同事查看机器负载,发现我们组内一个Java 服务占用的内存有点异常,启动命令-Xmx128m 指定了最大堆内存只有 128M,但是整个进程占用的内存达到了 640M,显然是有问题的

2. 线上排查

运维截图一扔,锅是甩不掉的,老老实实登录到线上机器排查。内存占用过高首先想到的就是发生了内存泄露,使用 Jmap -histo $pid > heap.log 输出堆内对象统计情况到文件中,查看文件发现堆中占用内存最多的是各种数组,没有发现明显的问题。没法子,使用 top -H p $pid命令检查该进程内运行的线程状况,终于发现了可疑点,在这个Java 服务里面运行的子线程居然有 5000 个,并且几乎全部都在 Sleeping 状态

 

 这种情况首先想到的是发生了线程死锁,资源争用导致大量线程被阻塞了。使用 jstack -l $pid > stack.log 将线程栈相关状况输出到文件中,打开文件一搜索却大失所望,根本没有死锁发生。线程状态大都在 TIMED_WAITING,不过随着一行行往下看,也发现了一个可疑点,以下这种 OkHttp ConnectionPool 的线程出现得太多了,线程序号甚至达到了1082707

"OkHttp ConnectionPool" #1082707 daemon prio=5 os_prio=0 tid=0x00007f564c18f000 nid=0x1a4d in Object.wait() [0x00007f5602cb4000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:460)
        at okhttp3.ConnectionPool$1.run(ConnectionPool.java:67)
        - locked <0x00000000fc30fb30> (a okhttp3.ConnectionPool)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - <0x00000000fc305f98> (a java.util.concurrent.ThreadPoolExecutor$Worker)

 

posted @ 2022-10-17 15:45  红豆奶茶+红豆  阅读(1748)  评论(0)    收藏  举报