开源java性能分析工具_使用开源工具进行有效的Java分析

开源java性能分析工具

一次又一次地出现了对正在运行的应用程序进行深入研究的需求。 造成这种情况的原因可能包括服务缓慢,JVM崩溃,挂起,死锁,频繁的JVM暂停,突然或持续的高CPU使用率,甚至是可怕的OutOfMemoryError(OOME)。 好消息是,有许多工具可用于从运行的JVM中提取各种初步信息,从而使您能够获得诊断此类情况所需的“幕后”视图。

在本文中,我将介绍一些可用的开源工具。 这些工具中的一些是JVM本身附带的,而有些是第三方工具。 我将以最简单的工具开始,然后随着本文的进展逐步转向更复杂的工具。 主要目的是使您能够扩展诊断工具箱,当您的应用程序开始执行奇怪的,缓慢的或根本不执行的工作时,这肯定会派上用场。

因此,让我们开始吧。

如果您的应用程序遇到异常高的内存负载,频繁冻结或OOME,从了解内存中存在哪种对象开始,它通常最有用。 幸运的是,JVM通过内置工具“ jmap”开箱即用。

Jmap(在JPM的帮助下)

Oracle将jmap描述为“打印给定进程或核心文件或远程调试服务器的共享对象内存映射或堆内存详细信息”的应用程序。 在本文中,我们将使用jmap打印出内存直方图。

为了运行jmap,您需要知道要针对其运行jmap的应用程序的PID。 一种简单的获取方法是使用JVM提供的工具jps ,该工具将列出计算机上运行的每个JVM进程以及每个进程的PID。 jps的输出如下所示:

开源java性能分析工具_使用开源工具进行有效的Java分析

图1: jps命令的终端输出

要打印出内存直方图,我们将调用jmap控制台应用程序,并传入应用程序的PID和“ -histo:live”选项。 如果没有此选项,jmap将对应用程序的堆内存进行完整的转储(在这种情况下,这不是我们想要的)。 因此,如果我们想从上图检索“ eureka.Proxy”应用程序的内存直方图,则将jmap调用为:

jmap –histo:live 45417

上面命令的输出可能类似于以下内容:

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图2: jmap -histo:live命令的输出,显示了来自堆的活动对象计数

生成的报告为我们显示了堆上当前每种类类型的行,以及它们分配的实例数和消耗的总字节数。

对于此示例,我让同事故意向应用程序添加了相当大的内存泄漏。 与下面的快照(仅在4分钟后拍摄)相比,请特别注意第8行CelleData上的类:

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图3: jmap输出显示了CelleData类增加的对象数

请注意, CelleData类现在已成为系统中的第二大类,在这4分钟内增加了631,701个实例。 当我们再快一个小时左右时,我们会注意到以下几点:

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图4:应用程序启动一小时后的jmap输出,显示了2500万个CelleData类实例

现在,有超过2500万个CelleData类实例,占用了超过1GB的内存! 我们发现了泄漏。

该数据的好处在于,它不仅有用,而且即使对于非常大的JVM堆,也非常容易掌握。 我已经在使用17GB堆内存的繁忙应用程序中进行了尝试,并且jmap能够在大约一分钟内生成其直方图。

请注意,jmap不是配置文件工具,并且JVM可能在直方图生成过程中停止,因此请确保应用程序在生成直方图所需的时间暂停以使其可接受。 但是,以我的经验来看,调试严重的错误时通常会更频繁地生成直方图,因此在这种情况下可以暂停应用程序一分钟。 这使我很好地进入了下一个主题–半自动分析工具VisualVM

虚拟机

JVM中当前内置的另一个工具是VisualVMVisualVM的创建者将其描述为“集成了多个命令行JDK工具和轻量级分析功能的可视工具”。 因此,VisualVM是您最有可能在事后进行检查的工具,或者至少在通过更传统的方式确定了严重的错误或性能问题(客户投诉是该类别中最主要的问题)之后才启动。

我们将继续前面的示例应用程序及其严重的内存泄漏问题。 在运行约30分钟后,VisualVM建立了以下图表:

开源java性能分析工具_使用开源工具进行有效的Java分析

图5:初始应用程序运行的VisualVM内存图

通过此图,我们可以清楚地看到,在仅运行10分钟之后的7:00 pm,该应用程序已经消耗了超过1GB的堆空间。 又过了23分钟,JVM达到了–Xmx3g阈值的上限,导致应用程序非常慢,系统速度很慢(垃圾收集常量)以及OOME数量惊人。

使用jmap确定了这种爬升的原因,然后进行了修复,我们在VisualVM的严格监督下使该应用程序再次运行,并观察以下内容:

开源java性能分析工具_使用开源工具进行有效的Java分析

图6:修复内存泄漏后的VisualVM内存图表

如您所见,应用程序的内存曲线(仍然使用–Xmx3g启动)看起来要好得多。

除了内存绘图工具外,VisualVM还提供了一个采样器和一个轻量级的探查器

VisualVM Sampler使您可以定期对应用程序进行采样以了解CPU和内存的使用情况。 可以获得与jmap相似的统计信息,并具有对方法调用的CPU使用率进行采样的附加功能。 这使您可以快速概览一下方法的执行时间,并定期进行采样:

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图7: VisualVM方法执行时间表

VisualVM Profiler将为您提供与采样器相同的信息,但是与其以固定的间隔对应用程序进行采样以获取信息,它可以在整个正常的应用程序执行过程中(通过应用程序源的字节码检测)从应用程序中收集统计信息。 与采样器收集的数据相比,您从此探查器获得的统计信息将更准确,更频繁地更新。

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图8: VisualVM Profiler的输出

但是,您必须考虑的另一面情况是,探查器是一种“强力”探查器。 它的检测方法实质上将重新定义应用程序正在执行的大多数类和方法,因此可能会大大降低应用程序的速度。 例如,使用上面使用的应用程序运行正常分析的一部分,则该应用程序在大约35秒内完成。 打开VisualVMs内存探查器会使应用程序在31分钟内完成相同的分析。

了解VisualVM不是功能齐全的探查器,因为它无法持续针对生产JVM运行。 它不会保留其数据,也无法指定阈值并在违反这些阈值时发送警报。 为了能够更接近功能齐全的探查器的目标,让我们接下来看一下功能齐全的开源Java代理BTrace

BTrace

想象一下,能够告诉实时生产JVM确切的信息类型是您想要收集的信息(以及因此而忽略的信息)。 该列表是什么样的? 我想这个问题的答案因人而异,因场景而异。 我个人通常对以下统计数据最感兴趣:

  • 应用程序“堆”,“非堆”,“永久代”以及JVM具有的不同内存池(新一代,终身代,幸存者空间等)的内存使用情况
  • 应用程序中当前处于活动状态的线程数,以及对正在使用的线程类型的深入分析(带有单独的计数)
  • JVM的CPU负载
  • 系统平均负载/系统总CPU使用率
  • 对于我的应用程序中的某些类和方法,我想查看调用计数,平均自执行时间和平均挂钟时间。
  • SQL调用的调用次数和执行时间
  • 磁盘和网络操作的调用计数和执行时间

BTrace可以收集以上所有信息,并且您可以使用BTrace脚本指定要收集的信息。 BTrace脚本的好处是它只是一个普通的Java类,其中包含一些特殊的注释,用于指定BTrace将在何处以及如何对应用程序进行检测。 BTrace编译器-btracec将BTrace脚本编译为标准.class文件。

BTrace脚本由多个部分组成,如下图所示。 有关下面显示的脚本的更详尽的演练,请访问此链接以及BTrace项目的网站

由于BTrace只是一个代理,因此在记录其结果后便完成了其工作。 BTrace除了以文本输出之外,没有任何功能可以动态地向您展示它以任何其他形式收集的信息。 默认情况下,BTrace脚本的输出将最终位于btrace .class文件旁边的文本文件中,称为YourBTraceScriptName.class.btrace

可以将额外的参数传递给BTrace,以使其在指定的时间间隔内对其日志文件进行日志轮换。 请记住,到达* .class.btrace.99后,它只会跨100个文件进行日志轮转,它将覆盖* .class.btrace.00文件。 如果将旋转间隔保持在合理的水平(例如,每7.5秒一次),则应该有足够的时间来处理输出。 要启用此日志轮换,请将fileRollMilliseconds = 7500参数添加到Java代理输入参数。

BTrace的一大缺点是其原始的,难以导航的输出格式。 您确实会想要一种更好的方式来处理BTrace输出和数据,最好是在一致的图形用户界面中。 您还将受益于比较不同时间点的数据的能力,以及在违反阈值时发送警报的能力。 这是新的开源工具EurekaJ出现的地方。

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图9:启用方法分析的BTrace脚本的必需部分

尤里卡

我从2008年开始编写EurekaJ 。当时,我正在寻找一种开放源代码工具,该工具具有我在Profiler中寻找的功能,但找不到它,因此我开始编写自己的工具。 在开发过程中,我研究了各种不同的技术,并访问了许多体系结构模型,最后得出了EurekaJ的第一版。 您可以阅读有关EurekaJ历史的更多信息,查看其源代码或下载并尝试从项目的网站上自己复制。

EurekaJ通常提供两个主要应用程序:

  1. 一个基于Java的“管理器”应用程序,它将接受传入的统计信息并提供以一致方式可视化统计信息的视图,以及
  2. 代理应用程序,它将解析BTrace输出,将其转换为JSON并将其转发到EurekaJ Manager应用程序的REST接口。

EurekaJ的输入数据接受两种数据格式。 EurekaJ Proxy希望将BTrace脚本输出格式化为以逗号分隔的文件(很容易从BTrace中获取),而EurekaJ Manager希望其输入遵循其JSON REST接口格式。 这意味着您可以通过代理应用程序或直接通过REST接口进行通信并传递指标。

使用EurekaJ Manger,可以将多个统计信息分组到一个图表中,以定义阈值,并通过电子邮件警报接收者。 收集的数据可以实时查看,也可以查看历史记录。

所有收集的数据都被整理到一个逻辑树结构中,该结构由BTrace脚本的作者决定。 建议BTrace脚本作者考虑对相关统计信息进行分组,以使它们以后在EurekaJ中更易于访问和发现。 例如,我个人喜欢将统计信息按逻辑分组,如下所示。

开源java性能分析工具_使用开源工具进行有效的Java分析

图10: EurekaJ演示应用程序中的统计信息组示例

图表范例

收集的一项重要指标是执行应用程序的系统上的平均负载。 如果您遇到运行缓慢的应用程序,则故障实际上可能不在于该应用程序内,而是可以隐藏在承载该应用程序的计算机上的其他位置。 我试图调试定期缓慢的应用程序,其中真正的罪魁祸首是病毒扫描程序。 如果您没有任何度量依据,这些事情可能很难弄清楚。 考虑能够访问显示平均系统负载以及您的过程在系统上生成的负载的图表。 下面的图表显示了当前正在运行EurekaJ演示应用程序的Amazon EC2虚拟服务器在2个小时内的平均负载(您可以使用用户名和密码“ user”登录到该应用程序 )。

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图11: EurekaJ图表显示平均系统负载

上表中的黄线和红线表示警报阈值。 一旦图表爬到黄线上方至少达到警报指定的最短时间,指标就会达到“警告”状态。 类似地,当红线被破坏时,指标达到其“严重”或“错误”状态。 每次状态之间的警报转换时,EurekaJ都会向注册收件人发送一封电子邮件。

在上述情况下,似乎每20分钟发生一次周期性事件,导致平均负载图表中出现峰值。 您可能要确保的第一件事是,该尖峰确实是由您的应用程序而不是其他地方生成的。 我们也可以通过测量进程CPU负载来验证这一点。 通过从树菜单中选择两个指标,EurekaJ可以使您快速可视化,EurekaJ会在两个菜单下显示两个图表。

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图12:一次显示多个图表

在上面的示例中,很明显,进程的CPU使用率与整个系统负载之间存在有意义的关联。

许多应用程序要求在应用程序无响应或不可用时立即向某人发出警报。 下图是从Confluence的安装中获得的示例,Confluence是Atlassian的企业Wiki软件。 在此示例中,应用程序的内存使用量Swift增加,达到了应用程序仅用尽内存的程度。 那时,Confluence无法处理传入的请求,并且日志中充满了各种奇怪的错误。

您可能希望应用程序在应用程序内存不足后立即引发OOME,但是实际上,直到JVM确定垃圾收集速度很慢,JVM才会引发OOME。 结果,该应用程序没有完全崩溃,并且Java在另外两个小时内也没有报告OutOfMemoryError,即使两个小时后,该应用程序仍在“运行”(这意味着JVM进程仍处于活动状态)。 显然,任何过程监视工具都不会将应用程序标识为“停机”。

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图13: EurekaJ堆图显示了内存不足错误的一种可能情况

该图表着重介绍了运行的最后几个小时,它揭示了以下指标。

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图14:放大上一个图表

使用EurekaJ,可以并建议在应用程序堆内存上定义警报。 如果应用程序始终使用超过95%-98%(取决于您的总体堆大小),则您的应用程序肯定存在内存问题,您必须使用–Xmx参数为该应用程序分配更多的堆。了解如何编写代码以使用更少的内存。 此外,计划在将来的EurekaJ版本中提供对丢失的统计信息发出警报的功能。

最后一个图表示例显示一个图表组,该组显示了四个不同应用程序的内存使用情况。 这种类型的图表分组使比较来自应用程序不同部分甚至跨应用程序和服务器的数据变得容易。 下面列出的四个应用程序都有非常不同的内存需求和不同的内存使用模式。

如下图所示,不同的应用程序具有不同的内存曲线。 这些曲线非常取决于许多因素,这些因素包括使用哪种框架,使用的缓存量,用户数以及应用程序的负载等。我提供了以下图表,以说明对您来说有多重要了解应用程序在正常负载和高负载下的行为,因为这将极大地影响您定义警报阈值的方式。

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图15:EurekaJ图表组将图表相互叠加

注意表演的成功–保持冷点凉爽!

您收集的每个度量都可能以某种方式对系统造成性能影响。 有些度量标准可以被视为“免费”(或“便宜”),而另一些度量标准则很昂贵。 知道BTrace的要求非常重要,这样可以最大程度地减少性能分析对应用程序造成的影响。 考虑以下三个原则:

  • 基于“样本”的测量通常可以被认为是“免费”的。 如果每5-10秒对CPU负载,进程CPU负载,内存使用情况和线程计数进行一次采样,则所产生的毫秒数或毫秒数可以忽略不计。 我认为,您应该始终收集这些类型的指标的统计信息,因为它们不会花费您任何费用。
  • 长时间运行的任务的度量也可以视为“免费”。 通常,每种被分析的方法将导致1700-2500纳秒。 如果要测量SQL查询的执行时间,网络流量,磁盘访问或在Servlet中完成的处理,而Servlet可能期望其性能介于40毫秒(光盘访问)到每秒一秒(Servlet处理)之间,这些方法中的每一个大约2500纳秒也是可以忽略的。
  • 永远不要为循环内执行的方法添加度量

通常,您要查找应用程序的热点,同时要注意避免冷点。 例如,考虑以下类:

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图16:我们可能要分析的简单数据访问对象类的示例

根据第5行上定义SQL的执行时间, readStatFromDatabase方法可能是一个热点。 如果查询返回大量行,这将成为热点,这将对第13行(应用程序和数据库服务器之间的网络流量)和第14-16行(其中的每一行所需的处理)产生负面影响结果集)。 如果数据库花费很长时间返回结果,则该方法也将成为热点(第13行)

buildNewStat方法 但是,它本身可能永远不会成为热点。 即使它可以执行很多次,每次调用也将在几纳秒内完成。 另一方面,每次执行SQL时,为每次调用添加2500纳秒的度量收集命中数无疑将使该方法看起来像一个热点。 因此,我们希望避免对其进行度量。

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图17:显示要分析的上述类的哪些部分以及应避免的部分

全部设置

使用EurekaJ的完整性能分析设置包含以下主要部分:

  • 您想要监视/仪器的应用程序
  • BTrace – Java代理
  • BTrace脚本告诉BTrace要测量什么
  • 您可以在其中存储BTrace输出的文件系统
  • EurekaJ代理将BTrace输出传输到EurekaJ Manager
  • EurekaJ Manager的安装(可以在本地局域网上,也可以通过Internet远程访问)

(点击图片放大)

开源java性能分析工具_使用开源工具进行有效的Java分析

图18:一种可能的体系结构的概述,该体系结构允许使用本文介绍的工具进行应用程序性能分析

有关每种产品的完整安装指南,请访问EurekaJ项目网站。

摘要

在本文中,我们已经探讨了一些开放源代码工具的优势,这些工具可以在需要对运行的JVM进行深入分析时使用,也可以在需要使用更广泛,更广泛的JVM时使用。使用探查器工具持续监视您的开发/测试/生产应用程序部署。

希望您已经开始看到不断收集度量标准的好处,并且可以在为应用程序设置的定义阈值被破坏时得到提醒。

谢谢!

参考资料

[1] jmap文档

[2] BTrace脚本概念

[3] BTrace项目现场

[4] EurekaJ现场演示

[5] EurekaJ Project网站

关于作者

开源java性能分析工具_使用开源工具进行有效的Java分析 Joachim Haagen Skeie在挪威奥斯陆的Kantega AS担任Java和Web技术方面的高级顾问,对应用程序分析和开源软件都非常感兴趣。 可以通过他的Twitter帐户联系。

翻译自: https://www.infoq.com/articles/java-profiling-with-open-source/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

开源java性能分析工具