在复杂的生产环境中定位 Java 内存问题,无论是隐蔽的内存泄漏还是由高频对象创建引发的 GC 压力,始终是性能工程中的一大挑战。传统的堆转储 (Heap Dump) 分析方法,不仅可能引发“Stop-the-World” (STW) 导致服务长时间停顿,而且其“离线尸检”的模式也使分析过程极为耗时,且难以捕捉瞬时问题。

本文将分享一种非侵入式的“在线分析”实践。我们将通过一个订单系统的案例,展示如何利用 OpenResty XRay,在不暂停服务、不依赖安全点的前提下,系统化地诊断运行中 JVM 的内存问题。您将看到我们如何通过三个步骤层层递进,精准定位问题:

  • 定位泄漏:使用 GC 对象引用分析,快速找到非预期的内存驻留根源。
  • 排查抖动:通过 GC 对象分配次数分析,发现高频创建对象的代码路径。
  • 优化体积:利用 GC 对象分配大小分析,定位“大对象”的创建源头。

1. 背景与问题

在一次客户的订单系统的性能回归测试中,我们观察到一个典型的内存异常现象:应用的堆内存曲线呈持续上升趋势,即便在多次 Full GC 之后,堆空间占用仍未见明显回落

根据工程经验,这种现象通常指向两个潜在问题:

  1. 存在内存泄漏 (Memory Leak),即部分对象在失去引用后本应被回收,但由于非预期的 GC Root 引用链存在,导致它们常驻内存。
  2. 在特定的业务路径上存在高频的对象创建“抖动” (Memory Churn),即大量短暂对象的创建和销毁导致 Young GC 压力过大,进而频繁触发 Full GC。

传统的堆转储 (Heap Dump) 分析方法,如使用 jmap 导出 HPROF 文件再通过 MAT 等工具离线分析,虽然功能强大,但在生产环境下面临挑战。导出数 GB 大小的堆快照本身会引发长时间的 STW (Stop-the-World),对线上服务是不可接受的。

为了在不中断服务、不引入明显性能开销的前提下进行“在线”诊断,我们采用 OpenResty XRay 对运行中的 JVM 进行分析。

2. 系统化的诊断路径:从泄漏到抖动

我们采用了“从面到点”的诊断策略,首先确认是否存在泄漏,然后排查分配频率与大小问题。

2.1 诊断内存泄漏:定位 GC Root

首要任务是确认是否存在内存泄漏,并找到泄漏源。我们使用了 OpenResty XRayGC 对象引用关系分析器

启动分析后,火焰图报告清晰地将内存中的对象分为两类:

  • Dead GC objects:已死亡、等待回收的对象(可忽略)。
  • 被 GC root 引用的对象:存活的对象(排查重点)。

我们重点排查后者。沿着 GC root 引用链逐层展开,分析工具清晰地指向了内存占用的集中点:OrderProcessingService$OrderService 实例。

Screenshot

进一步深入,发现内存主要被该实例的两个字段持有:

  • notificationQueue (一个并发队列)
  • paymentRecords (一个支付记录数组)

通过分析引用路径我们确认,这些集合中的对象本应在业务流程结束后被移除,但由于逻辑缺陷,导致它们的生命周期超出了预期,证实了内存泄漏点的存在。

2.2 分析分配频率:发现内存“抖动”

定位泄漏点后,第二个问题是:是否存在不必要的内存“抖动”?高频的内存分配会加剧 GC 压力,即使没有泄漏,也会拖累系统吞吐量。

通过 OpenResty XRayGC 对象分配次数分析器,我们得到了按代码路径分类的对象创建频率火焰图。

报告显示,createOrder 方法 (@OrderProcessingService.java:118) 的对象创建次数,也就是火焰图中的宽度,要显著高于其他业务路径。

高频的对象创建,尤其是进入老年代,会导致 Young GC 频繁触发,并且可能加速老年代的填充,这会增加 STW 时间,进而拖慢 P99 响应延迟。

2.3 分析分配大小:揪出“大对象”

最后,我们检查了“大对象”问题,即是否存在某些路径在频繁创建体积庞大的对象。

我们切换到 GC 对象分配大小分析器。GC 对象分配火焰图按照采样区间内创建的 GC 对象总大小进行统计。创建的对象总大小越大,在图上的占比越高。

分析报告指出,generateOrderId 方法 (@OrderProcessingService.java:155) 及其下游调用,虽然在次数上不占优,但在内存体积占用上却非常突出,主要原因是频繁创建了体积较大的字符串对象。

经评估,该 ID 生成逻辑有很高的重复率,适合引入缓存。通过对字符串生成逻辑进行缓存化改造,我们显著降低了该路径的堆占用峰值。

3. 诊断效率与系统增益

借助 OpenResty XRay 的三个分析器,我们在短时间内完成了从现象到根因的完整闭环定位。

  • 诊断效率提升:过去依赖传统 heap dump 工具,需要反复比对与手动追踪引用链;而使用 XRay 的火焰图后,仅需几分钟即可直观看到问题集中区域,大幅缩短了排查路径。
  • 系统性能改善:修复问题后,GC 时间占比明显下降,应用在相同负载下的响应更加平稳,整体延迟曲线趋于稳定。

更重要的是,这次实践带来了方法论上的变化。OpenResty XRay 的可视化分析让团队成员能直接理解对象在内存中的生命周期与引用关系。调优讨论从“凭经验猜测”转向“基于证据决策”,让性能优化变得更具确定性。

4. 为什么选择 OpenResty XRay 分析 Java 应用中的内存?

传统的 Java 内存分析严重依赖 Heap Dump。这种“离线尸检”式的分析方式,存在其固有的局限性。

传统 Heap Dump 工具核心局限
需暂停或重启进程1. 导出堆快照(jmap)通常会触发 STW,导致生产服务长时间停顿。
分析成本高2. 堆文件体积庞大(动辄几 GB),传输与加载耗时。
数据时效性差3. 只能分析当时的快照,无法观察系统实时变化。

OpenResty XRay 提供了另一种思路:非侵入式的“在线分析”。它在设计上规避了传统工具的痛点。

  1. 生产环境安全 OpenResty XRay 无需重启 Java 进程,也不必修改代码或替换 JDK。它通过安全的 attach 机制直接连接正在运行的 JVM,对业务透明。

  2. 极低开销与非侵入性 这是 OpenResty XRay 的核心技术优势。它不依赖 JVM 安全点 (Safepoint) 机制进行采样。这意味着它可以在不触发任何 STW (Stop-the-World) 的前提下,对 JVM 的内存、CPU、I/O 等进行分析。这使其成为少数真正敢在实时生产流量下执行深度诊断的工具。

  3. 直观的可视化分析 它提供的 GC 对象引用火焰图和内存引用路径图,能直观展示“谁引用了谁”、“内存去哪了”,极大降低了内存问题的分析门槛。

  4. 多维度的性能画像

OpenResty XRay 不仅限于内存。在本次案例中,我们虽然聚焦于 GC,但也可以随时切换到 CPU 火焰图、I/O 分析等,结合上下文构建一个完整的系统性能画像。

这种设计让 OpenResty XRay 成为少数真正可在 生产环境实时分析 Java 内存问题 的工具之一。在上面的订单系统案例中,它帮助团队实现了“实时诊断 + 快速验证”的闭环,避免了停机分析的风险。

5. 总结与思考

在此次订单系统的内存问题排查中,OpenResty XRay 帮助我们构建了一个系统化的诊断流程:从“是否泄漏”到“频率问题”再到“对象体积”;从“引用关系”到“分配次数”再到“分配大小”层层递进,缩小排查范围。

这种基于实时采样与可视化的分析范式,能有效替代传统的 heap dump + 离线分析路径。它不仅提升了诊断效率,更重要的是,它为高并发、高可用的 Java 服务在生产环境中的性能调优,提供了一种更安全、更高效的解题思路。

关于 OpenResty XRay

OpenResty XRay 是一款动态追踪产品,它可以自动分析运行中的应用,以解决性能问题、行为问题和安全漏洞,并提供可行的建议。在底层实现上,OpenResty XRay 由我们的 Y 语言驱动,可以在不同环境下支持多种不同的运行时,如 Stap+、eBPF+、GDB 和 ODB。

关于作者

章亦春是开源 OpenResty® 项目创始人兼 OpenResty Inc. 公司 CEO 和创始人。

章亦春(Github ID: agentzh),生于中国江苏,现定居美国湾区。他是中国早期开源技术和文化的倡导者和领军人物,曾供职于多家国际知名的高科技企业,如 Cloudflare、雅虎、阿里巴巴, 是 “边缘计算“、”动态追踪 “和 “机器编程 “的先驱,拥有超过 22 年的编程及 16 年的开源经验。作为拥有超过 4000 万全球域名用户的开源项目的领导者。他基于其 OpenResty® 开源项目打造的高科技企业 OpenResty Inc. 位于美国硅谷中心。其主打的两个产品 OpenResty XRay(利用动态追踪技术的非侵入式的故障剖析和排除工具)和 OpenResty Edge(最适合微服务和分布式流量的全能型网关软件),广受全球众多上市及大型企业青睐。在 OpenResty 以外,章亦春为多个开源项目贡献了累计超过百万行代码,其中包括,Linux 内核、Nginx、LuaJITGDBSystemTapLLVM、Perl 等,并编写过 60 多个开源软件库。

关注我们

如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:

我们的微信公众号

翻译

我们提供了英文版原文和中译版(本文)。我们也欢迎读者提供其他语言的翻译版本,只要是全文翻译不带省略,我们都将会考虑采用,非常感谢!