Java 堆转储包含如此多的信息,以至于识别 JVM 内存泄漏的原因就像大海捞针一样。而且,从生产系统中检查 Java 堆转储可能会让你在不知不觉中拥有个人身份信息,如果处理不当,可能会给你带来各种隐私问题,这会使整个文件感觉具有放射性。
检查 Java 堆转储根本不值得麻烦,如果不是因为这样做几乎是修复 JVM 中 Java 内存泄漏的唯一方法。或者至少在 Java Flight Recorder 引入 Old Object Sample 事件之前,这是唯一的方法。
使用 Java Flight Recorder 进行 JVM 堆分析
以下是 Java Flight Recorder 的 Old Object Sample 事件的工作原理。开始记录时,将跟踪 Java 堆中固定数量的对象。Java 堆对象的跟踪属性包括:
对象的分配开始时间
对象的持续时间
关联事件线程
最后已知的堆大小使用情况
对象类型
垃圾收集根
你可以通过调整旧对象队列大小来调整 Flight Recorder 跟踪的 Java 堆上的对象数量:
-XX:FlightRecordingOptions=old-object-queue-size=512
JDK Mission Control 内存泄漏检测
当 Java 堆上的跟踪对象被垃圾回收时,它会从样本中删除并添加一个新对象。随着时间的推移,导致内存泄漏的对象更有可能被跟踪。JVM Flight Recorder 运行的时间越长,就越有可能跟踪导致内存泄漏的对象。
此外,这些导致 Java 内存泄漏的对象存在的时间越长,它们消耗的内存越多,当需要检查 Java Mission Control 中的 JVM Flight Recording 时,它们的存在就越明显。
此外,Java Mission Control 中的规则引擎能够识别哪些长时间运行的 Java 堆对象最有可能导致 JVM 内存泄漏。
请注意,在 Java Flight Recorder 在旨在触发内存泄漏的示例应用程序上运行后,Java Mission Control 立即指示通过旧对象示例事件监视的对象可能是罪魁祸首:
在录制过程中,堆上的 live set 似乎以每秒 192 KiB 的速度增加。
对参考树的分析发现了 1 个泄漏候选者。主要候选是 java.util.Hashtable$Entry[] 被这个链引用:
java.util.Hashtable.table
se.hirt.jmc.tutorial.memleak.Leak$DemoThread.table
Java 堆上的活动对象
随着初始自动分析,Java Mission Control 将提供一个列表,指示堆上所有活动项目的大小,以及内存中所有活动对象的列表。如你所见,无需借助 JVM 堆转储,即可轻松识别 Java 内存泄漏。
内存泄漏检测最佳实践
显然,内存泄漏检测示例中的示例是一个简单的示例。要在更复杂的示例中识别违规对象,请遵循以下内存泄漏检测最佳实践:
长时间运行 Java Flight Recorder。这增加了违规对象的变化以进行采样。查看在 JVM 上消耗最多内存的对象。
查看在 JVM 上消耗最多内存的对象。
取消在 JVM 启动时分配的对象的优先级。进程初始化会产生很多噪音。
在飞行记录器运行中间分配的对象比在开始或结束时分配的对象更可能是罪魁祸首。
监视 Java 类加载器外部引用的守护线程。
密切关注:静态变量、缓存数据、长时间运行的线程。
添加自定义触发器以在满足某些内存消耗阈值时启动 Java Flight Recorder。
通过对自定义 Flight Recorder 事件进行编码并在潜在问题点启动它们,将遥测添加到你的 Java 应用程序。
在内存问题成为严重程度为 1 的生产问题之前,积极主动地监控应用程序的内存问题。
JVM Flight Recorder 和 JDK Mission Control
JVM Flight Recorder 和 JDK Mission Control 提供了多种高级功能,使开发人员无需检查复杂的 Java 堆转储即可解决 Java 内存泄漏问题。熟悉这些强大的分析和监控工具,解决 Java 性能问题将不再是一项繁琐的任务。
发表评论 取消回复