JProfiler帮助文档Download

线程分析


不正确地使用线程会导致许多不同类型的问题。过多的活动线程可能导致线程饥饿,线程可能会互相阻塞并影响应用程序的活性,或者以错误的顺序获取锁可能导致死锁。此外,关于线程的信息对于调试目的也很重要。

在 JProfiler 中,线程分析分为两个视图部分:“Threads”部分处理线程的生命周期和捕获线程转储。“Monitors & locks”部分提供分析多个线程交互的功能。

检查线程

线程历史视图在时间线上显示每个线程为一条彩色行,其中颜色表示记录的线程状态。线程按创建时间、名称或线程组排序,并可以按名称过滤。您还可以通过拖放自行重新排列线程的顺序。当监视器事件被记录时,您可以悬停在线程的“Waiting”或“Blocked”状态部分,并查看与监视器历史视图的链接的相关调用栈。

所有线程的表格视图可在线程监视器视图中使用。如果在创建线程时 CPU 记录处于活动状态,JProfiler 会保存创建线程的名称并在表中显示。在底部,显示创建线程的调用栈。出于性能原因,不会从 JVM 请求实际的调用栈,而是使用 CPU 记录中的当前信息。这意味着调用栈将仅显示满足调用树收集过滤器设置的类。

如果您在分析设置中启用估算 CPU 时间的记录,则会在表中添加一个CPU Time列。仅在记录 CPU 数据时测量 CPU 时间。

像大多数调试器一样,JProfiler 也可以进行线程转储。线程转储的调用栈是 JVM 提供的完整调用栈,不依赖于 CPU 记录。选择两个线程转储并单击Show Difference按钮时,可以在差异查看器中比较不同的线程转储。还可以通过选择单个线程转储中的两个线程并从上下文菜单中选择Show Difference来比较它们。

线程转储还可以通过“Trigger thread dump”触发器操作或通过API进行。

分析锁定情况

每个 Java 对象都有一个关联的监视器,可用于两种同步操作:线程可以在监视器上等待,直到另一个线程在其上发出通知,或者它可以获取监视器上的锁,可能会阻塞,直到另一个线程放弃锁的所有权。此外,Java 在java.util.concurrent.locks包中提供了用于实现更高级锁定策略的类。该包中的锁不使用对象的监视器,而是使用不同的本机实现。

JProfiler 可以记录上述两种机制的锁定情况。在锁定情况下,有一个或多个线程、一个监视器或java.util.concurrent.locks.Lock的实例以及一个需要一定时间的等待或阻塞操作。这些锁定情况以表格形式在监视器历史视图中呈现,并在锁定历史图中以可视化方式呈现。

锁定历史图关注所有涉及的监视器和线程的整个关系集,而不是孤立监视器事件的持续时间。参与锁定情况的线程和监视器被绘制为蓝色和灰色矩形,如果它们是死锁的一部分,则绘制为红色。黑色箭头表示监视器的所有权,黄色箭头从等待线程延伸到关联的监视器,而虚线红色箭头表示线程想要获取监视器并且当前正在阻塞。如果记录了 CPU 数据,则在悬停在阻塞或等待箭头上时可以查看调用栈。这些工具提示包含超链接,可带您到监视器历史视图中的相应行。

表格监视器历史视图显示监视器事件。它们有一个显示为列的持续时间,因此您可以通过对表进行排序来找到最重要的事件。对于表格视图中选择的任何行,您可以通过Show in Graph操作跳转到图形。

每个监视器事件都有一个关联的监视器。Monitor Class列显示使用监视器的实例的类名,如果没有 Java 对象与监视器关联,则显示“[raw monitor]”。无论如何,监视器都有一个唯一的 ID,显示在单独的列中,因此您可以关联多个事件中相同监视器的使用情况。每个监视器事件都有一个执行操作的等待线程和一个可能阻塞操作的拥有线程。如果可用,它们的调用栈显示在视图的下部。

如果您对监视器实例有进一步的问题,监视器历史视图和锁定历史图中的Show in Heap Walker操作提供了一个链接到堆行走器,并选择监视器实例作为新的对象集。

限制感兴趣的事件

分析监视器事件的一个基本问题是应用程序可能会以极高的速率生成监视器事件。这就是为什么 JProfiler 对等待和阻塞事件有默认阈值,低于该阈值的事件会立即被丢弃。这些阈值在视图设置中定义,可以增加以便专注于更长的事件。

对于记录的事件,您可以进一步应用过滤器。监视器历史视图在视图顶部提供了一个阈值、一个事件类型和一个文本过滤器。锁定历史图允许您选择感兴趣的线程或监视器,并仅显示涉及标记实体的锁定情况。感兴趣的事件在时间线上以不同的颜色显示,并且有一个次级导航栏可以逐步浏览这些事件。如果当前事件不是感兴趣的事件,您可以看到当前事件与任一方向上的下一个感兴趣事件之间有多少事件。

除了选择的线程或监视器存在的锁定情况外,还显示从图中删除它的锁定情况。这是因为每个监视器事件由两个这样的锁定情况定义,一个是操作开始时,一个是操作结束时。这也意味着完全空的图形是一个有效的锁定情况,表示 JVM 中没有更多的锁。

另一种减少需要您关注的事件数量的策略是累积锁定情况。在锁定历史图中,底部有一个时间线,显示所有记录的事件。单击并拖动它可以选择一个时间范围,并在上面的锁定图中显示所有包含事件的数据。在累积图中,每个箭头可以包含多个相同类型的事件。在这种情况下,工具提示窗口显示事件的数量以及所有包含事件的总时间。工具提示窗口中的下拉列表显示时间戳,并允许您在不同事件之间切换。

死锁检测

“Current locking graph”和“Current monitors”视图在 JProfiler UI 中通过一个动作触发的“monitor dump”上运行。通过监视器转储,您可以检查仍在进行中的事件。这包括死锁,这些事件永远不会完成,无法在历史视图中显示。

阻塞操作通常是短暂的,但在发生死锁时,这两个视图将显示问题的永久视图。此外,当前锁定图显示导致死锁的线程和监视器为红色,因此您可以立即发现此类问题。

进行新的监视器转储将替换两个视图中的数据。您还可以通过“Trigger monitor dump”触发器操作或通过API触发监视器转储。

监视器使用统计

为了从更高的角度调查阻塞和等待操作,监视器统计视图从监视器记录数据中计算报告。您可以按监视器、线程名称或监视器类对监视器事件进行分组,并分析每行的累积计数和持续时间。