记录数据
分析器的主要目的是记录来自各种来源的运行时数据,这些数据对解决常见的问题很有用。这项任务的主要问题是,运行JVM会以极快的速度生成这些数据。 如果分析器总是记录所有类型的数据,就会产生不可接受的开销,或者很快就会耗尽所有可用的内存。此外,你通常希望记录围绕一个特定用例相关的数据, 不希望看到任何不相关的活动。
这就是为什么JProfiler提供了细粒度的机制来控制你真正感兴趣的信息的记录。
标量值和遥测
从分析器的角度来看,问题最少的数据形式是标量值,例如活跃线程数或打开的JDBC连接数。 JProfiler可以以固定肉眼可见的频率-通常是每秒一次对这类值进行采样,并向你展示随时间的演变。 在JProfiler中,显示此类数据的视图称为遥测。 大多数遥测数据总是会被记录,因为这种测量的开销和内存消耗都很小。如果数据被记录了很长时间,旧的数据点会被合并, 这样内存消耗就不会随着时间线性增长。
还有一些参数化的遥测,比如每个类的实例数量。额外的维度使得永久的时间记录变得不可持续。 你可以告诉JProfiler对一些选定类而不是每个类的实例数记录遥测。
继续前面的例子,JProfiler能够向你展示所有类的实例计数,但没有顺序信息。 这就是"所有对象"视图,它在表格中每个类显示一行,更新视图的频率低于每秒一次,可能会根据测量造成的开销大小自动调整。 确定所有类的实例计数成本比较高,而且堆上的对象越多,需要的时间越长。JProfiler限制了"所有对象"视图的更新频率, 因此在极端情况下,测量的开销永远不会超过10%。 你可以冻结视图来暂时停止记录。 另外,如果视图不活动,数据将不会被记录,也不会有相应的开销。
有些测量可以捕获类枚举值,例如线程当前所处的执行状态,这种测量可以以彩色时间线的形式显示,比数值遥测消耗的内存少很多。 在线程状态的例子中,"线程历史"视图显示了JVM中所有线程的时间顺序。就像数值遥测一样,旧的值会被合并,并变得更加粗粒度,以减少内存消耗。
分配记录
如果你对某个时间间隔内被分配的实例计数感兴趣,JProfiler必须跟踪所有分配。与"所有对象"视图相反, JProfiler可以遍历堆中的所有对象以按需获取信息,而跟踪单次分配则需要为每次对象分配执行额外的代码。 这使得它成为一种非常昂贵的测量方法,会显著改变被分析应用程序的运行时特征,例如性能热点,特别是当你分配了许多对象时。 这就是为什么必须显式启动和停止分配记录的原因。
相关的记录视图初始会显示一个空页面,上面有一个记录按钮。也可以在工具栏中发现同样的记录按钮。
分配记录不仅记录分配的实例数量,还记录分配堆栈跟踪。在内存中保留每个分配记录的堆栈跟踪会造成过多的开销, 所以JProfiler将记录的堆栈跟踪累积成一棵树。这样做还有一个好处,就是你可以更容易解释数据。 但是,失去了时间顺序相关数据,而且没有办法从数据中提取指定时间范围。
内存分析
分配记录只能测量对象的分配位置,没有对象之间的引用信息。任何需要引用的内存分析,如解决内存泄漏,要在堆遍历器中完成。 堆遍历器会对整个堆生成一个快照并对其分析。这是一个侵入性的操作,会暂停JVM-可能会暂停很长时间-并且需要大量的内存。
更轻量级的操作是在开始一个用例之前标记堆上的所有对象,这样在稍后生成堆快照时就可以找到所有新分配的对象。
JVM有一个特殊的触发器,用于将整个堆转储到一个以旧HPROF分析代理命名的文件中。这与分析接口无关,也不在其限制下操作。 由于这个原因,HPROF堆转储速度更快,使用的资源更少。缺点是,当你在堆遍历器器中查看堆快照时,你将没有与JVM的实时连接, 并且一些功能不可用。
方法调用记录
测量方法调用耗费的时间是一种可选的记录,就像分配记录。方法调用会累积成一棵树,有各种视图从不同的角度显示记录的数据,比如调用图。 这类数据的记录在JProfiler中称为"CPU记录"。
在特殊情况下,查看方法调用的时间顺序可能非常有用,特别是当涉及到多个线程时。对于这些特殊情况, JProfiler提供了"调用跟踪器"视图。该视图有一个单独的记录类型,不与更普遍的CPU记录绑定。 需要注意的是,调用跟踪器产生的数据太多,对解决性能问题没有用处,它只是为了一种特殊的调试形式使用。
调用跟踪器依赖于CPU记录,必要时自动开启。
另一个自带记录功能的专门视图是"复杂度分析"。它只测量选定方法的执行时间,不需要启用CPU记录。 它的附加数据轴是一个方法调用的算法复杂度数值,你可以用脚本计算。 这样,你可以测量一个方法的执行时间究竟多大程度取决于它的参数。
Monitor记录
为了分析线程为什么等待或阻塞,必须记录相应的事件。这类事件的发生率差异很大。 对于线程频繁协调任务或共享公共资源的一个多线程程序来说,可能会有大量的此类事件。 这就是为什么默认情况下不记录这种时间顺序严谨的数据。
当您打开Monitor记录时,"锁状态历史图"和"Monitor历史"视图将开始显示数据。
为了消除噪音和减少内存消耗,非常短的事件不会被记录。通过视图设置,您可以调整这些阈值。
探针记录
探针显示JVM中更高层次的子系统,如JDBC调用或文件操作。默认情况下,不记录探针,你可以为每个探针分别切换记录。 有些探针会增加很少或没有开销,有些探针会创建大量数据,这取决于你的应用程序正在做什么以及探针是如何配置的。
就像分配记录和方法调用记录,探针数据是累计的,除了时间线和遥测之外,其他的时间顺序信息都被丢弃了。 然而,大多数探针还有一个"事件"视图,允许你检查单个事件。这潜在的增加了一个大开销,和一个单独的记录动作。 该记录操作的状态是持久的,所以当你切换探针记录时,如果你之前已经打开了它,那么相关的事件记录也会被切换。
JDBC探针有第三个记录操作,用于记录JDBC连接泄漏。只有当你真正试图调查这样的问题时,才会产生寻找连接泄漏的相关开销。 就像事件记录操作,泄漏记录操作的选择状态是持久的。
记录分析
在很多情况下,你想通过一次点击开始或停止各种记录。逐个访问所有相应视图,逐个切换记录按钮是不切实际的。 这就是为什么JProfiler有记录分析。记录分析可以通过点击工具栏中的开始记录按钮创建。
记录分析定义了一个可以原子化激活的特定记录组合。JProfiler试图让你对所选记录产生的开销有一个粗略的印象, 并试图阻止有问题的组合。特别是,分配记录和CPU记录并不能很好地组合在一起,因为CPU数据的计时会被分配记录严重扭曲。
您可以在会话运行时随时激活记录分析。记录分析不是叠加的,它们会停止所有未包含在记录分析中的记录。 通过停止记录按钮,您可以停止所有的记录,无论它们是如何被激活的。 要查看当前激活的记录有哪些,请将鼠标悬停在状态栏的记录标签上。
也可以直接在启动分析时激活一个记录分析。在"会话启动"对话框中有一个 初始化记录分析下拉菜单。 默认情况下,不选择任何记录分析,但如果你需要JVM启动阶段的数据,这里是配置所需记录的地方。
使用触发器记录
有时你想在某个特定条件发生时开始记录。JProfiler有一个定义触发器的系统, 可以执行一系列操作。可用的触发操作也包括改变激活记录。
例如,你可能想要仅当某个特定方法执行时才启动一个记录。在这种情况下,你可以进入会话设置对话框,激活 触发器设置选项卡, 并为该方法定义一个方法触发器。对于操作配置,您有许多不同的记录动作可用。
"开始记录"操作可以控制那些没有任何参数的记录。通常情况下,当您停止和重新开始记录时,所有之前记录的数据都会被清除。 对于"CPU数据"和"分配数据"的记录,你也可以选择保留之前的数据,并在多个时间段内继续累加。
通过使用上下文菜单中的"添加方法触发器"操作,可以在调用树中方便地添加方法触发器。 如果在同一个会话中已经有了方法触发器,可以选择在现有的触发器上添加方法拦截。
默认情况下,当JVM被启动进行分析时,触发器是激活的。有两种方法可以在启动时禁用触发器: 你可以在触发器配置中单独禁用它们,或者取消选择会话启动对话框中的启动时启用触发器复选框, 在实时会话期间,你可以通过选择菜单中的分析→(启用|禁用)触发器或 点击状态栏中的 触发器记录状态图标启用或禁用所有触发器。
有时,你需要同时为触发器组切换触发激活。这可以通过为感兴趣的触发器指定相同的组ID, 然后调用菜单中的分析→启用触发器组实现。
使用jpcontroller记录
JProfiler有一个命令行可执行文件,用于控制已经被分析的任何JVM中的记录。 jpcontroller要求发布JProfiler MBean,否则它将无法连接到被分析的JVM。这仅限于分析代理已经接收到分析设置。 如果没有分析设置,代理将不知道到底要记录什么。
必须满足以下条件之一:
- 你已经通过一个JProfiler GUI连接到JVM了。
-
分析的JVM通过
-agentpath
VM参数启动,该参数包含nowait
和config
参数。 这和集成向导中的立即启动模式和配置同步步骤的在启动时应用配置选项相对应 。 -
JVM已经使用
可执行文件为分析析做了准备,并且指定了 jpenable
-offline
参数。 更多信息请参见的输出。 jpenable -help
特别是,如果分析的JVM只使用nowait
标志启动, 将无法工作。
在集成向导中,配置同步步骤中与JProfiler GUI连接时应用配置选项将配置这样一个参数。
jpcontroller
jpcontroller为你提供了一个循环的多级菜单,可以显示所有的记录及其参数。你也可以用它保存快照。
编程方式启动分析
还有另一种启动分析的方式是通过API。在分析的VM中,你可以调用com.jprofiler.api.controller.Controller
类以编程方式开始和停止记录。请参阅离线分析章节,了解更多信息以及如何获得包含控制器类的工件。
如果你想控制不同JVM中的记录,你可以访问被分析JVM中也被使用的相同MBean。
设置MBean的编程方式使用有点复杂,涉及很多规则,所以JProfiler附带了一个例子,你可以重复使用。
查看文件 jpcontroller
api/samples/mbean/src/MBeanProgrammaticAccessExample.java
。
它在另一个被分析JVM中记录了5秒钟的CPU数据,并将快照保存到磁盘上。