一次线上OOM的分析处理

起因

收到线上报警。发现老年代满了,CGC直接回收不了。导致内存溢出。


image.png

环境

线上环境使用的java17,垃圾回收器使用的ZGC。
表象原因
从线上拉取之前保存的dump.hprof文件。导入mat(eclipse memory analyzer)中。

  1. 从图可以看出
ThreadPoolExecutor    370.4 MB
其他对象               约2.5 GB(饼图中2个浅色区块)
未分类内存             355.2 MB(深蓝色区块)
image.png
  1. 从报告来看
  • 线程池泄露(Problem Suspect 1/3/4):
    • 多个ThreadPoolExecutor实例总占用2.6GB+
    • 特征:工作队列无限积压任务(截图3/4显示工作线程ws-exe-3/7关联泄露)
  • WebSocket泄露(Problem Suspect 2):
    • 278个WsFrameServer实例占用576MB
    • 根源:Tomcat的WsServerContainer持有未释放的WebSocket连接
    • 直接关联线程:http-nio-0.0.0.0-8228-exec-9
image.png
image.png
image.png
image.png
  1. 内存分析
    主要泄漏对象
  • ThreadPoolExecutor实例(地址0x8001a2e5940):
    • 通过workQueue字段持有LinkedBlockingQueue@0x8001a2e59a8,表明线程池任务队列积压。
  • SdwanWsSessionRegistry实例(地址0x80034c7ed28):
    • 维护WebSocket会话(SdwanWsSession),但未正确清理失效会话。
  • 多个工作线程(如ws-exe-4、ws-exe-5等):
    • 持有SdwanWsSession或XtermWsServer对象,线程未释放导致关联对象无法回收。
      典型泄漏对象
  • SdwanWsSession(WebSocket会话)
  • ThreadPoolExecutor(线程池)
  • ConcurrentHashMap(用于存储会话的注册表)


    image.png

总结: 从报告上来看,是工作线程消息挤压。然后线程池又是无界队列。消息堆积导致了OOM。
深层原因
上面我们分析到了消息堆积。下面我们继续查找是什么原因导致的。从线程概况列表看出。主要问题出在了ws-exe-3和ws-exe-6两个线程上。

image.png

ws-exe-3

我们点开ws-exe-3详情页。可以看到该线程是出于无限期等锁的状态[alive, parked, waiting, waiting indefinitely]。


image.png

该线程持有了XtermWsSessionRegistry的写锁(remove方法)。想要去拿取SdwanWsSessionRegistry 中的读锁。处于等待读锁中。


image.png

ws-exe-6

该线程也是处于无线等锁的状态。


image.png

从详情看出。该线程持有SdwanWsSessionRegistry的写锁。在尝试去拿XtermWsSessionRegistry的读锁。处于等锁状态中。


image.png

结论

从上面分析来看。ws-exe-3和ws-exe-6形成了死锁循环链。导致消息堆积。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容