JProfiler帮助文档

数据记录

profiler(分析器)的主要用途是从各种来源记录运行时数据,以帮助解决常见问题。此任务的主要难点在于,运行中的JVM会以极高的速率生成此类数据。 如果profiler始终记录所有类型的数据,将会带来不可接受的开销,或者很快耗尽所有可用内存。此外,您通常只希望围绕特定用例记录数据,而不希望看到无关的活动。

这就是JProfiler为您提供细粒度控制信息记录机制的原因,您可以只记录自己真正关心的数据。

标量值与遥测 (telemetries)

从profiler的角度来看,最不成问题的数据形式是标量值,例如活动线程数或打开的JDBC连接数。JProfiler可以以固定的宏观频率(通常为每秒一次)对这些值进行采样,并展示其随时间的变化。在JProfiler中,展示这类数据的视图被称为遥测 (telemetries)。大多数遥测 (telemetries) 始终被记录,因为测量的开销和内存消耗都很小。如果长时间记录数据,较早的数据点会被合并,以避免内存消耗随时间线性增长。

也有参数化的遥测 (telemetries),比如每个类的实例数。多出这一维度后,永久按时间顺序记录就不可持续了。您可以让JProfiler只记录选定类的实例数遥测 (telemetries),而不是每个类都记录。

延续上面的例子,JProfiler能够展示所有类的实例数,但不包含时间顺序信息。这就是“All objects”视图,每个类作为表格中的一行展示。该视图的刷新频率低于每秒一次,并可能根据测量带来的开销自动调整。统计所有类的实例数相对开销较大,堆中的对象越多,耗时越长。因此,“All objects”视图不会自动刷新,您需要手动创建新的对象快照(dump)。

有些测量会捕获类似枚举的值,例如线程当前所处的执行状态。这类测量可以以彩色时间线的方式展示,内存消耗远小于数值型遥测 (telemetries)。以线程状态为例,“Thread history”视图会展示JVM中所有线程的时间线。与数值型遥测 (telemetries) 一样,较早的值会被合并并变得更粗粒度,以减少内存消耗。

分配 (allocation) 记录

如果您关注某个时间区间内被分配 (allocated) 的实例数,JProfiler需要跟踪所有分配 (allocation)。与“All objects”视图中JProfiler可以按需遍历堆中所有对象不同,跟踪单个分配 (allocation) 需要为每次对象分配 (allocation) 执行额外代码。这使得该测量非常昂贵,可能显著改变被分析 (profiled) 应用的运行时特性,比如性能热点 (hot spot),尤其是在您频繁分配 (allocate) 对象时。因此,分配 (allocation) 记录需要显式地启动和停止。

具有相关记录的视图初始会显示一个空页面和一个记录按钮。该记录按钮也可以在工具栏中找到。

分配 (allocation) 记录不仅记录分配 (allocated) 实例的数量,还会记录分配 (allocation) 的调用栈 (call stack)。如果为每次分配 (allocation) 记录都在内存中保存调用栈 (call stack),会带来极大的开销,因此JProfiler会将记录的调用栈 (call stack) 累积到一棵树中。这也带来了更易于解读数据的好处。但时间顺序信息会丢失,无法从数据中提取特定时间区间。

内存分析

分配 (allocation) 记录只能测量对象的分配 (allocation) 情况,无法获取对象之间的引用信息。任何需要引用关系的内存分析(如定位内存泄漏)都在堆遍历器(heap walker)中完成。堆遍历器会对整个堆进行快照并分析。这是一个侵入式操作,会暂停JVM(可能持续较长时间),并需要大量内存。

更轻量的操作是,在开始用例前标记堆中所有对象,这样在之后进行堆快照时,您可以找到所有新分配 (allocated) 的对象。

JVM有一个专门的触发器 (trigger) 用于将整个堆转储到文件,该功能以旧的HPROF分析代理命名。这与分析接口无关,也不受其约束。因此,HPROF堆转储速度更快,资源占用更少。缺点是,在堆遍历器中查看堆快照时,您无法与JVM保持实时连接,部分功能也不可用。

方法调用 (method call) 记录

测量方法调用 (method call) 所用时间是一项可选记录,和分配 (allocation) 记录类似。方法调用 (method call) 会被累积到一棵树中,并有多种视图从不同角度展示记录的数据,比如调用图 (call graph)。此类数据的记录在JProfiler中称为“CPU recording”。

在某些情况下,查看方法调用 (method call) 的时间顺序尤其有用,特别是涉及多个线程时。针对这些特殊场景,JProfiler提供了“调用跟踪器 (Call tracer)”视图。该视图有独立的记录类型,不依赖于更通用的CPU recording。请注意,调用跟踪器 (call tracer) 产生的数据量过大,不适合解决性能问题,仅用于特定形式的调试。

调用跟踪器 (call tracer) 依赖于CPU recording,并在需要时自动开启。

另一个有独立记录的专用视图是“复杂度分析 (Complexity analysis)”。它只测量选定方法的执行时间,无需启用CPU recording。其额外的数据轴是方法调用 (method call) 的算法复杂度数值,您可以通过脚本计算。这样,您可以衡量方法执行时间与其参数的关系。

Monitor recording

为了分析线程为何处于等待或阻塞状态,需要记录相关事件。这类事件的发生频率差异很大。对于多线程程序,线程频繁协调任务或共享资源时,相关事件数量可能极大。因此,这类时间顺序数据默认不被记录。

当您开启monitor recording后,“Locking history graph”和“Monitor history”视图将开始显示数据。

为了消除噪声并减少内存消耗,极短的事件不会被记录。视图设置允许您调整这些阈值。

探针 (probe) 记录

探针 (probe) 展示JVM中的高层子系统,如JDBC调用或文件操作。默认情况下,不会记录任何探针 (probe),您可以为每个探针 (probe) 单独切换记录。有些探针 (probe) 几乎不会带来开销,有些则会根据应用行为和探针 (probe) 配置产生大量数据。

与分配 (allocation) 记录和方法调用 (method call) 记录类似,探针 (probe) 数据会被累积,时间顺序信息会被丢弃,除了时间线和遥测 (telemetries)。不过,大多数探针 (probe) 也有一个“Events”视图,允许您检查单个事件。这会带来较大开销,并有独立的记录操作。该记录操作的状态是持久的,因此当您切换探针 (probe) 记录时,如果之前已开启事件记录,相关事件记录也会一同切换。

JDBC探针 (probe) 还有第三种记录操作,用于记录JDBC连接泄漏 (connection leak)。只有在您实际调查此类问题时,才会产生查找连接泄漏 (connection leak) 的相关开销。与事件记录操作一样,泄漏记录操作的选择状态也是持久的。

记录配置文件 (recording profile)

在许多场景下,您希望通过一次点击同时启动或停止多项记录。逐个进入相关视图并切换记录按钮会很繁琐。这就是JProfiler引入记录配置文件 (recording profile) 的原因。您可以通过点击工具栏中的Start Recordings按钮创建记录配置文件 (recording profile)。

记录配置文件 (recording profile) 定义了一组可以原子激活的记录组合。JProfiler会尝试为您大致估算所选记录带来的开销,并尽量避免有问题的组合。尤其是分配 (allocation) 记录和CPU recording不建议同时开启,因为分配 (allocation) 记录会显著影响CPU数据的计时。

在会话 (session) 运行期间,您可以随时激活记录配置文件 (recording profile)。记录配置文件 (recording profile) 不是叠加的,它会停止所有未包含在配置文件中的记录。通过Stop Recordings按钮,您可以停止所有记录,无论它们是如何被激活的。要查看当前激活了哪些记录,将鼠标悬停在状态栏中的记录标签上即可。

记录配置文件 (recording profile) 也可以在启动分析时直接激活。“Session startup”对话框有一个Initial recording profile下拉框。默认情况下未选择任何记录配置文件 (recording profile),但如果您需要JVM启动阶段的数据,可以在此处配置所需的记录。

使用触发器 (trigger) 进行记录

有时您希望在特定条件发生时启动记录。JProfiler有一套定义触发器 (trigger) 的系统,可以执行一系列操作。可用的触发器 (trigger) 操作也包括更改当前激活的记录。

例如,您可能只想在某个方法被执行时才开始记录。在这种情况下,您可以进入会话 (session) 设置对话框,激活Trigger Settings标签页,并为该方法定义一个方法触发器 (trigger)。在操作配置中,您可以选择多种不同的记录操作。

“Start recording”操作会直接控制这些记录,无需任何参数。通常情况下,当您停止并重新启动记录时,之前记录的数据会被清除。对于“CPU data”和“Allocation data”记录,您还可以选择保留之前的数据,并在多个区间内继续累积。

可以在调用树 (call tree) 中通过右键菜单的“Add method trigger”操作方便地添加方法触发器 (trigger)。如果同一会话 (session) 已有方法触发器 (trigger),您可以选择为现有触发器 (trigger) 添加方法拦截。

默认情况下,触发器 (trigger) 在JVM启动分析时处于激活状态。禁用触发器 (trigger) 有两种方式:可以在触发器 (trigger) 配置中单独禁用,也可以在会话 (session) 启动对话框中取消选中Enable triggers on startup复选框。在实时会话 (session) 中,您可以通过菜单Profiling→(Enable|Disable) Triggers或点击状态栏中的  触发器 (trigger) 记录状态图标来启用或禁用所有触发器 (trigger)。

有时,您需要同时切换一组触发器 (trigger) 的激活状态。可以为感兴趣的触发器 (trigger) 分配相同的组ID,然后通过菜单Profiling→Enable Trigger Groups来实现。

使用jpcontroller进行记录

JProfiler提供了一个命令行可执行文件,用于控制已被分析 (profiled) 的任意JVM中的记录。 jpcontroller要求JProfiler MBean已发布,否则无法连接到被分析 (profiled) 的JVM。只有在分析代理已收到配置文件设置 (profiling setting) 的情况下才会发布MBean。没有配置文件设置 (profiling setting),代理不会知道具体要记录什么。

必须满足以下条件之一:

  • 您已通过JProfiler GUI连接到JVM
  • 被分析 (profiled) 的JVM是通过包含-agentpath参数,并同时指定nowaitconfig参数启动的。在集成向导中,这对应于Startup immediately模式和Apply configuration at startup选项,在Config synchronization步骤中设置。
  • JVM已通过 jpenable可执行文件和-offline参数为分析做了准备。更多信息请参见 jpenable -help的输出。

具体来说,如果被分析 (profiled) 的JVM仅使用nowait标志启动, jpcontroller将无法工作。在集成向导中,Apply configuration when connecting with the JProfiler GUI选项(在Config synchronization步骤中)会配置此参数。更多信息请参见 关于启动时设置配置文件设置 (profiling setting) 的帮助主题

jpcontroller会为所有记录及其参数提供一个循环的多级菜单。您也可以用它保存快照。

以编程方式启动记录

还有一种启动记录的方式是通过API。在被分析 (profiled) 的VM中,您可以调用com.jprofiler.api.controller.Controller类,以编程方式启动和停止记录。更多信息以及如何获取包含controller类的artifact,请参见离线分析章节

如果您想控制其他JVM中的记录,可以访问被分析 (profiled) JVM中同样用于 jpcontroller的MBean。以编程方式使用MBean的配置稍显繁琐,需要一些额外步骤,因此JProfiler附带了可复用的示例。请查看文件api/samples/mbean/src/MBeanProgrammaticAccessExample.java。它会在另一个被分析 (profiled) 的JVM中记录5秒的CPU数据,并将快照保存到磁盘。