基于DevKit Java性能分析工具的调优实践——内存泄露问题
发表于 2025/12/29
0
1 调优概述
鲲鹏DevKit是一款提供涵盖迁移、测试、性能调优及系统诊断等各环节的开发使能工具集。其中,DevKit Java性能分析工具是针对基于鲲鹏的服务器上运行的Java程序的性能分析和优化工具,能图形化显示Java程序的堆、线程、锁、垃圾回收等信息,收集热点函数、定位程序瓶颈点,帮助用户采取针对性优化。本文使用Java性能优化工具对运行中的Java程序进行在线分析和采样分析,找到程序中的内存泄漏问题,并根据分析结果进行优化修改,从而实现Java程序最佳运行。
2 环境要求
|
项目 |
说明 |
|
服务器 |
TaiShan 200 服务器(型号2280) |
|
CPU |
Kunpeng 920 |
|
OS |
CentOS 7.6 |
| 调优工具 | Kunpeng DevKit Java性能分析工具 |
3 前提条件
- 服务器和操作系统正常运行
- PC端已经安装SSH远程登录工具
- 需要优化的Java程序
4 调优思路
- 使用Java性能优化工具对Java进程进行在线分析;
- 使用Java性能优化工具对Java进程进行采样分析;
- 针对性能的瓶颈点进行性能优化;
- 观察优化后的Java程序,判断问题是否解决。
5 调优过程
5.1 准备工作
步骤1:登录Java性能优化工具
步骤2:添加目标环境(待分析的Java进程所在的服务器)

步骤3:启动在线分析功能

5.2 概览页签查看进程的整体情况
概览分析:通过概览页面发现程序的堆使用情况在一段时间内不断升高,同时GC也比较频繁,但是堆却没有明显的被释放,可能存在内存泄露。

5.3 GC页签查看GC的具体情况
分析发现 GC 比较频繁,有 YoungGC 和 OldGC,但是每次GC 回收的内存可以忽略不计,甚至根本没有回收任何内存,此现象说明内存泄露的可能性很大

5.4 内存转储查看具体信息
1、在内存转储页签下 点击 执行内存转储按钮 生成堆转储文件,为了方便查看堆的变化可以保存快照,生成多次堆转储文件。


2、通过生成两次堆转储文件发现 TestMemoryLeak$Person 这个类应该是自定义的类,内存占用情况比较多,并且随着时间呈上升趋势,需要重点观察。可以利用快照功能提供的比较操作,方便查看两个堆转储文件中相同类实例与保留堆的变化情况,通过比较发现 TestMemoryLeak$Person 实例与保留堆是明显上升的趋势。

3、切换到支配树模式,发现 TestMemoryLeak 类的保留堆占总堆的比例高达 97%,继续向下点开支配树发现大部分对象是 TestMemoryLeak$Person 持有的 byte[],到这里正好可以跟直方图中byte[] 占比较多可以对应的上。


4、经过直方图与支配树的分析,TestMemoryLeak$Person类对应的实例有内存泄露嫌疑,根据支配树提供的内容 应该是 HashSet 实例 持有 TestMemoryLeak$Person 对象,接下来咱们可以搜索代码中的相关项看看。
本案例中的demo 程序比较简单,直接搜索 TestMemoryLeak 类可以发现的确存在内存泄露点,
一个线程不断的往HashSet和HashSetPerson两个静态对象添加Person实例,并且没有清除的逻辑,导致出现内存泄露。

5.5 采样分析查看是否有内存泄露的报告
对目标程序进行采样分析,最好进行多次采样,采样时间相对长一点。


查看采样分析中的内存 à 老年代对象页签 发现有一份内存泄露发现的报告。
TestMemoryLeak.hashSet 和 TestMemoryLeak.hashSet 两个对象是内存泄露的源头,结果与在线分析一致
5.6 优化 Java程序
通过 在线分析 和 采样分析 大致定位到内存泄露的点后,就需要根据功能提供的类、实例以及引用链信息 去查看具体的业务代码,然后根据情况具体分析代码修改策略。
如本案例中的程序,如果把它看成是一个保存缓存数据的场景,我们就可以加入定期清除的策略。
优化后代码:

5.7 优化后的 Java程序
优化后的程序通过概览页即可发现内存使用正常、GC活动正常

6 实践总结
本次实践中,对一Java程序进行了内存泄漏的发现与解决,通过在线分析和采样分析发现了程序中的内存泄漏点,进而优化程序中的内存泄漏点达到优化程序性能的目的。在进行其他程序调优时,需要根据Kunpeng Devkit性能优化工具采集分析的实际结果和对应的优化建议进行调优操作。具体的调优思路可以参考本次实践。


