最近项目上线前压测,服务跑着跑着就卡了,CPU 正常但内存一路飙升。同事小李第一反应是:‘怕不是又哪里内存泄漏了?’ 其实这种情况在日常开发中并不少见,尤其是用 Java 做后端服务时,对象创建频繁,稍不注意就会留下隐患。好在我们有 IntelliJ IDEA 这样的利器,配合一些技巧,定位内存泄漏并不难。
为什么内存泄漏总在关键时刻出问题?
想象一下,你正在写一份重要的年终汇报 PPT,开了十几个浏览器标签查资料,还挂着视频会议和微信沟通。电脑一开始还挺流畅,可过一会儿就开始卡顿,风扇狂转——不是硬件不行,而是资源被悄悄耗尽。程序也一样,哪怕 JVM 有垃圾回收机制,如果某些对象本该被释放却一直被引用,它们就会堆积成山,最终拖垮整个应用。
IDEA 结合 JVM 参数,让问题无处藏身
要抓内存泄漏,光靠看代码很难发现线索。得让程序‘说话’。第一步是在启动时加上 JVM 监控参数:
-Xmx512m -Xms256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heapdump.hprof
这些参数的意思是:限制堆内存最大 512M,发生 OOM 时自动生成堆转储文件。虽然线上环境不会这么设,但在测试阶段足够暴露问题。运行一段时间后,如果出现性能下降,直接用 IDEA 打开生成的 .hprof 文件。
用 IDEA 自带工具查看堆快照
打开 IDEA,选择 ‘File’ → ‘Open’,导入 heapdump.hprof。它会自动调用内置的 Memory View 工具。进去之后你会看到一张直观的饼图,显示各类对象占用内存的比例。点击占比高的类,比如 UserSession 或 CacheMap,右侧会列出所有实例。
有一次我们发现某个缓存 Map 里存了几万个 Entry,而正常情况下不应该超过几百个。点进去一看,key 是用户 ID,value 是 session 对象,但很多用户早就登出了,session 却没清理。问题根源找到了:注册监听器时忘了反注册,导致对象一直被持有。
实战技巧:对比多个快照找出增长点
单看一次堆快照只能知道‘现在谁占得多’,但不知道‘是谁慢慢变多的’。更好的方式是:在系统刚启动时拍一个快照,运行一小时后再拍一个,然后在 IDEA 中使用 ‘Compare with Another Heap Dump’ 功能。它会列出新增最多的类,一眼就能看出哪个对象在持续积累。
避免误判:区分真实泄漏和临时峰值
并不是所有内存上涨都是泄漏。有时候是批量任务处理大量数据,暂时占用较多内存,任务结束就释放了。这时候要看 GC 回收后的剩余量。在 IDEA 的 Dominator Tree 标签页里,关注 ‘Shallow Heap’ 和 ‘Retained Heap’ 数值,如果多次 Full GC 后依然居高不下,那才可能是真正的泄漏。
养成习惯,把内存检查纳入日常
就像每天上班前整理桌面一样,写完一段核心逻辑后,花几分钟用 IDEA 跑一遍小型压力测试,抓个快照看看有没有异常对象堆积。早发现早解决,总比半夜被报警电话叫醒强。毕竟,谁不想下班准时走人呢?