在某些情况下,问题并不是方法的平均调用时间过长,而是该方法偶尔会出现异常行为。在调用树 (call tree) 中,所有方法调用都会被累计,因此一个被频繁调用的方法即使每 10000 次调用中有一次耗时比预期多 100 倍,也不会在总耗时中留下明显的痕迹。
为了解决这个问题,JProfiler 在调用树中提供了异常值 (outlier) 检测视图 (view) 和异常方法 (exceptional methods) 记录功能。
异常值 (outlier) 检测视图 (view)
异常值 (outlier) 检测视图会展示每个方法的调用持续时间、调用次数,以及单次调用的最大耗时。最大调用耗时与平均耗时的偏差可以反映所有调用持续时间是否集中在一个较小的区间,或者是否存在显著的异常值 (outlier)。异常值系数 (outlier coefficient) 的计算方式如下:
(最大耗时 - 平均耗时) / 平均耗时
可以帮助你量化方法在这方面的表现。默认情况下,表格会按照异常值系数 (outlier coefficient) 从高到低排序。只有在已记录 CPU 数据时,异常值 (outlier) 检测视图的数据才可用。
为了避免仅被调用几次的方法或极短运行方法带来的干扰,可以在视图 (view) 设置中为最大耗时和调用次数设置下限。默认情况下,只有最大耗时超过 10 ms 且调用次数大于 10 的方法才会显示在异常值 (outlier) 统计中。
配置异常方法 (exceptional methods) 记录
一旦你确定某个方法存在异常调用耗时,可以通过右键菜单将其添加为异常方法 (exceptional method)。同样的菜单操作也可以在调用树 (call tree) 视图 (view) 中使用。
当你为异常方法 (exceptional method) 启用记录后,调用树 (call tree) 会单独保留部分最慢的调用,其余调用则像往常一样合并为一个方法节点 (node)。单独保留的调用次数可以在配置文件设置 (profiling setting) 中进行配置,默认值为 5。
在区分慢方法调用时,必须选择某种线程状态用于耗时测量。这不能依赖 CPU 视图 (view) 中的线程状态选择,因为那只是显示选项而不是记录选项。默认情况下,使用 wall clock 时间,但也可以在配置文件设置 (profiling setting) 中配置不同的线程状态。异常值 (outlier) 检测视图 (view) 也会使用相同的线程状态。
在会话 (session) 设置中,你可以移除异常方法 (exceptional methods) 或添加新的异常方法,无需依赖调用树 (call tree) 或异常值 (outlier) 检测视图 (view)。此外,异常方法 (exceptional method) 配置还提供了为常见系统(如 AWT 和 JavaFX 事件分发机制)添加异常方法定义的选项,这些系统中异常耗时的事件往往是主要问题。
调用树 (call tree) 中的异常方法 (exceptional methods)
异常方法 (exceptional methods) 的运行 (run) 会在调用树 (call tree) 视图 (view) 中以不同方式显示。
拆分后的方法节点 (node) 会有不同的图标,并显示额外的文本说明:
-
[exceptional run]
[异常运行 (Exceptional Run)]
此节点包含一次异常缓慢的方法运行 (run)。根据定义,其调用次数为 1。如果后续有更多方法运行 (run) 更慢,该节点可能会消失,并根据配置的最大单独记录方法运行 (run) 数量被合并到“合并异常运行 (merged exceptional runs)”节点 (node) 中。 -
[merged exceptional runs]
[合并异常运行 (merged exceptional runs)]
不满足异常缓慢条件的方法调用会合并到此节点 (node)。对于每个调用栈 (call stack),每个异常方法 (exceptional method) 只会有一个这样的节点。 -
[current exceptional run]
[当前异常运行 (current exceptional run)]
如果在调用树 (call tree) 视图 (view) 传输到 JProfiler GUI 时某次调用正在进行中,尚无法判断该调用是否异常缓慢。“当前异常运行 (current exceptional run)”会显示当前调用的单独维护树。调用完成后,该节点会被保留为单独的“异常运行 (exceptional run)”节点 (node),或合并到“合并异常运行 (merged exceptional runs)”节点 (node) 中。
与通过探针 (probe)和拆分方法 (split methods)进行调用树 (call tree) 拆分类似,异常方法 (exceptional method) 节点 (node) 在右键菜单中有一个合并拆分级别 (Merge Splitting Level)操作,可让你随时合并或取消合并所有调用。











