做了这么多年程序员,你知道怎么解决内存泄漏问题吗?

你真的遇到过线上的OOM问题吗?真的遇到了你知道怎么处理吗?说实话这种问题还是需要一点一点去排查的,可能并没有你想的那么简单,不过也有可能没有你想的那么难!感兴趣的话可以3~5分钟看下,只讲有用的,不说废话!


1、前因

周三早上9点多,部门技术经理反馈需要协助看两个线上问题,这项目都是几年前的古董项目,很少有人动,更别说了解业务场景了,奈何打工人,只能说没问题...

2、问题描述

  • 问题一属于业务型问题,也是在我的猜测和生产日志两头辅助下,花费了一天的时间找到了问题所在,关键源代码还是猜的在哪个项目里面,也是无语了...

  • 问题二也是本文将要说的重点内容,OOM这种经常说但是不经常遇到的问题,因此本次做下记录...

3、工欲善其事,必先利其器

俗话说得好”工欲善其事,必先利其器“,要做OOM的分析,必经不是顶级大神看下日志就知道问题在哪,因此还是需要借助相应的工具的,由于是做OOM问题日志分析,因此最终决定在VisualVM 和MAT(Memory Analyzer Tool)两者之前选者一个,最终做了下对比,还是决定用MAT;

  • VisualVM

    功能特点:
        实时监控:VisualVM可以实时显示Java进程的CPU、内存、线程和GC(垃圾回收)等方面的信息,帮助开发者快速分析应用程序的性能和资源占用情况。
        线程分析:能生成应用程序的线程快照(Thread Dump),帮助识别死锁、饥饿和其他线程相关的问题。
        堆内存分析:可生成应用程序的堆内存快照(Heap Dump),用于分析内存泄漏、内存溢出等内存问题。
        CPU和内存分析器:提供CPU和内存的采样分析器和探查器,帮助找到性能瓶颈和内存泄漏。
        GC分析:显示垃圾回收的详细信息,有助于分析和优化垃圾回收策略。
        插件支持:支持通过插件扩展功能,增加工具的灵活性和可用性。
    优势:
        综合了多个JDK命令行工具的功能,提供图形化用户界面,操作直观方便。
        实时监控和分析功能强大,适合对Java应用程序进行全面的性能监控和资源分析。
  • MAT(Memory Analyzer Tool)

    功能特点:
        堆转储分析:专注于分析Java堆转储文件(Heap Dump),帮助开发者查找内存泄漏和减少内存消耗。
        对象分析:快速计算内存中对象的占用大小,查看阻止垃圾收集器回收工作的对象,并通过报表直观展示。
        报告生成:提供多种报告模式,如内存泄漏可疑点报告(Leak Suspects Report)和元件报告(Component Report),帮助开发者定位问题。
        数据视图:支持按类数量、浅堆(Shallow Heap)、深堆(Retained Heap)等多种视图展示数据,方便开发者深入分析。
    优势:
        专注于堆内存分析,功能丰富且深入,适合解决复杂的内存问题。
        提供直观的报表和视图,帮助开发者快速定位内存泄漏和消耗问题。

总结如下:

  • 如果是实时监控Java应用程序的性能和资源占用情况,包括CPU、内存、线程和GC等方面,那么VisualVM可能更适合你。它提供了一个全面的监控和分析平台,让你能够实时了解应用程序的运行状态。

  • 如果主要关注点是内存问题,特别是堆内存中的内存泄漏和消耗问题,那么MAT更适合。它专注于堆转储文件的分析,提供了丰富的功能和视图来深入分析了解内存使用情况。

4、资源准备

  • OOM日志文件hs_err_***.loghs_heapdp_**.hprof文件

  • MAT本地安装,具体安装步骤如下图:

5、hs_err_pid.log文件分析

5.1、文件结构说明
  • 日志头信息【重要】

    日期和时间:记录日志生成的具体时间。
    JVM版本信息:包括JVM实现的名称、版本、构建信息等。
    操作系统信息:如操作系统名称、版本、架构等。
    错误信号:如 SIGSEGV, SIGBUS 等,表示导致JVM崩溃的操作系统信号。
  • 错误摘要,导致crash的线程信息【重要】

    一条总结性的错误信息,如 "A fatal error has been detected by the Java Runtime Environment:",紧接着是具体的错误描述。显示引发崩溃的线程的详细信息,包括线程ID、线程名称以及堆栈跟踪。
  • 线程转储(Thread Dump),所有线程信息

    当前所有活动线程的状态,包括线程ID、线程名称、堆栈跟踪(stack trace)。这对于分析哪个线程引发了错误非常关键。一般存在内存泄漏的话就在这些线程里面。
  • 安全点和锁信息

    包括CPU寄存器的内容,这对于理解崩溃时的硬件状态很重要,特别是对于硬件相关的错误。描述了在崩溃时刻哪些线程持有锁,以及锁的状态,这对于分析死锁或竞争条件等问题非常有用。
  • 堆信息

    包括堆的大小、使用情况以及对象分配的统计信息,可以帮助诊断内存泄漏或内存不足的问题。
  • 本地代码缓存

    展示了JIT编译后的本地代码缓存,这对于理解性能问题和潜在的代码优化点有帮助。
    
  • 编译事件

    记录了JIT编译器的活动,包括编译的热点方法、编译级别等,有助于分析性能瓶颈。
    
  • gc相关记录【重要】

    包含最近的垃圾收集活动,包括收集的类型、前后堆的使用情况等,这对于分析GC相关的性能问题非常重要。
    
  • JVM内存映射和JVM启动参数

    显示了JVM在物理内存中的布局,包括各个内存区域的位置和大小,这对于诊断内存访问错误非常有用。列出了启动JVM时使用的命令行参数,这对于复现问题环境非常关键。
    
  • 服务器信息

    包括操作系统版本、处理器型号、CPU核心数等,这些信息有助于理解运行环境。
    
5.2、梳理出来的信息关键点

PS:通过hs_err_pid.log可以得出一个大体的结论:异常报错为oom,导致oom的线程为‘RxComputationScheduler-3’但是不一定是问题线程,只能说明刚好这个线程创建对象时内存溢出了,另外年轻代频繁GC说明大量创建新对象。

6、MAT分析hs_heapdp_pid.hprof文件

前提:File->Open Help Dump导入hprof文件,功能说明

  • Dominator tree

    功能 展现对象的支配关系图,并给出对象支配内存的大小(支配内存等同于 Retained Heap,即其被 GC 回收可释放的内存大小) 支持排序、支持按 package、class loader、super class、class 聚类统计。

    使用场景 开始 Dump 分析时,首先应使用 Dominator tree 了解各支配树起点对象所支配内存的大小,进而了解哪几个起点对象是 GC 无法释放大内存的原因。 当个别对象支配树的 Retained Heap 很大存在明显倾斜时,可以重点分析占比高的对象支配关系,展开子树进一步定位到问题根因,如下图中可看出最终是 TaskThread线程对象持有的 ArrayList 过大。

Class Name : 类名称,java类名**
Objects : 类的对象的数量,这个对象被创建了多少个**
Shallow Heap :一个对象内存的消耗大小,不包含对其他对象的引用**
Retained Heap :是shallow Heap的总和,也就是该对象被GC之后所能回收到内存的总和

基本上由上图我们已经初步判断出来问题所在了,下面就找一下,是哪个查询导致的问题
  • thread_view

主要用于查询线程的堆栈信息

找到对应的业务方法之后,需要配合oom异常时对应的业务日志进行判断,找oom时刻同样线程(11)的哪个业务日志基本上就能很快的定位到问题了,最终定位问题为一个查询条件未传入导致获取大量数据,我也是醉了...

问题已找到,不是什么大问题,但是查起来的确比较不容易,完结撒花,稍等,在告诉你一个小技巧...

7、使用技巧

  • Leak Suspects

功能:具备自动检测内存泄漏功能,罗列可能存在内存泄漏的问题点。

使用入口:一般当存在明显的内存泄漏时,分析完Dump文件后就会展现,也可以如下图在 MAT 主页 → Leak Suspects。

使用场景:需要查看引用链条上占用内存较多的可疑对象。这个功能可解决一些基础问题,但复杂的问题往往帮助有限。

是不是更容易,不过针对明显问题可以,看当前这个问题的饼图你就知道

8、参考文献

一文深度讲解JVM 内存分析工具 MAT及实践(建议收藏)-阿里云开发者社区 (aliyun.com)

MAT(Memory Analyzer Tool)工具使用超详细版-CSDN博客

Java程序内存分析:使用mat工具分析内存占用 - 孤剑 - 博客园 (cnblogs.com)

添加公众号了解更多,定期分享、绝对实用,绝对对你有帮助!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值