分析JVM


要想对一个JVM进行分析,JProfiler的分析代理必须被加载到该JVM中。这可以通过两种不同的方式实现: 通过在启动脚本中指定一个-agentpath VM参数,或者通过Attach API将代理加载到已经运行的JVM中。

两种模式JProfiler都支持。添加VM参数是分析的首选方式,集成向导、IDE插件和从JProfiler内启动JVM的会话配置都使用这种方式。 Attach既可在本地使用,也可通过SSH远程使用。

-agentpath VM参数

了解加载分析代理的VM参数的构成很有用。-agentpath是JVM提供的一个通用VM参数,用于加载任何一种使用JVMTI接口的本地库。 由于分析接口JVMTI是一个本地接口,所以分析代理必须是一个本地库。这意味着你只能在 明确支持的平台上进行分析。 32位和64位JVM也需要不同的本地库。另外,Java代理是用-javaagent VM参数加载的,并且只能访问有限的功能。

-agentpath: 后面附加本地库的完整路径名。有一个等效参数-agentlib:, 你只需要指定特定平台的库名,但必须确保库路径中包含该库。在库的路径之后,你可以添加一个等号,并向代理传递选项,用逗号隔开。例如,在Linux上,整个参数看起来可能像这样:

-agentpath:/opt/jprofiler10/bin/linux-x64/libjprofilerti.so=port=8849,nowait

第一个等号将路径名与参数分开,第二个等号是参数port=8849 的一部分。 这个常用参数定义了分析代理监听来自JProfiler GUI连接的端口,实际上8849是默认端口,所以也可以省略这个参数。 如果你想在同一台机器上分析多个JVM,必须分配不同端口, 不过IDE插件和本地启动的会话会自动分配这个端口,对于集成向导,你必须显式选择端口。

第二个参数nowait告诉分析代理不要在启动时为了等待JProfiler GUI连接而阻塞JVM。 启动时的阻塞是默认的,因为分析代理不是以命令行参数的形式接收其分析设置,而是从JProfiler GUI或配置文件接收。 命令行参数仅用于引导分析代理,告诉它如何启动和传递调试标记。

默认情况下,JProfiler代理将通信Socket绑定到所有可用的网络接口。如果出于安全原因不希望这样做, 你可以添加选项address=[IP地址]以便选择指定接口,或loopback 只监听来自本地机器的请求。对于通过JProfiler UI启动的或通过IDE集成的JVM,会自动添加loopback

本地启动的会话

就像IDE中的"Run configurations",你可以直接在JProfiler中配置本地启动的会话。 你指定类路径、主类、工作目录、VM参数和参数,JProfiler会为你启动会话。所有JProfiler附带的演示会话都是本地启动的会话。

一个特殊的启动模式是"Web启动",你选择JNLP文件的URL,JProfiler将启动一个JVM对其进行分析。 这个功能支持OpenWebStart,不支持Java9之前的Oracle JRE 的传统WebStart。

本地启动的会话可以通过调用主菜单中的转换向导会话->转换向导转换为独立的会话。 应用会话转换为远程会话简单地创建一个启动脚本,并将-agentpath VM参数插入到Java调用中。 应用会话转换为离线会话会为离线分析创建一个启动脚本,这意味着配置在启动时被加载,不需要JProfiler GUI。 应用会话转换为重分发会话做了同样的事情,但是在它旁边创建了一个目录jprofiler_redist , 其中包含了分析代理和配置文件,这样你就可以把它发送到没有安装JProfiler的其他机器上。

如果被分析应用程序是你自己开发,可以考虑使用IDE集成而不是启动会话。这样会更方便,并给你提供更好的源代码导航。 如果应用程序不是你自己开发,但已经有了启动脚本,可以考虑使用远程集成向导。它将告诉你必须添加到Java调用中的确切VM参数。

集成向导

JProfiler的集成向导可以处理许多知名的第三方容器,这些容器具有启动脚本或配置文件,可以通过编程修改以包含额外的VM参数。 对于某些产品,可以生成启动脚本,其中VM参数作为参数或通过环境变量传递。

在所有用例中,你必须定位第三方产品的一些特定文件,这样JProfiler才有需要的上下文来执行其修改。一些通用向导只给你必须做什么才能启用分析的操作指南。

每个集成向导的第一步是选择在本地机器上还是在远程机器上进行分析。在本地机器的情况下,你需要提供的信息更少,因为JProfiler已经知道平台,JProfiler的安装位置和它的配置文件的位置。

一个重要的决定是上面讨论过的"启动模式"。默认情况下,分析设置是在启动时从JProfiler UI中传输的,但你也可以告诉分析代理让JVM立即启动。在后一种情况下,一旦JProfiler GUI连接,就可以应用分析设置。

然而,你也可以通过分析设置配置同步步骤指定一个配置文件,这样更高效。 这种方式的主要问题是,每次你在本地编辑分析设置,必须要与远程端同步配置文件。 最优雅的方法是在远程地址步骤通过SSH连接到远程机器,然后通过SSH自动传输配置文件。

在集成向导最后,将创建一个会话,该会话将开始分析,并且--在非通用情况下--还会启动第三方产品,如应用服务器。

外部启动脚本由会话设置对话框中应用程序设置选项卡上的执行启动脚本执行停止脚本 选项处理,可以通过选择浏览器中打开URL复选框显示URL。这里也是你可以更改远程机器地址和配置同步选项的地方。

集成向导所有处理的情况是被分析JVM运行在远程机器上。但是,当配置文件或启动脚本必须修改时,你必须把它复制到本地机器上,然后把修改后的版本传回远程机器上。 直接在远程机器上运行命令行工具jpintegrate,让它在相应位置进行修改可能更方便。 jpintegrate需要JProfiler的完整安装,并且与JProfiler GUI的JRE要求相同。

当启动远程分析会话时发生错误,请参见故障排除指南,查看可用于解决问题的检查列表步骤。

IDE集成

分析应用程序最方便的方式是通过IDE集成。如果你通常在开发过程中从IDE启动你的应用程序,IDE已经有了所有需要的信息, JProfiler插件可以简单地添加VM参数进行分析,必要时启动JProfiler,并将被分析JVM连接到JProfiler主窗口。

所有的IDE集成都包含在JProfiler安装的integrations目录中。原则上, 该目录中的归档可以通过各自IDE的插件安装机制手动安装。但是,安装IDE集成的首选方式是调用主菜单中的会话->IDE集成

IDE中的分析会话在JProfiler中没有自己的会话条目,因为这样的会话无法从JProfiler GUI中启动。根据IDE中的设置,Profiling设置持久化在每个项目或每个运行配置的基础上。

当连接到IDE,JProfiler在工具栏中会显示一个窗口切换器,可以很容易跳回IDE中的相关窗口。所有显示源代码操作现在直接在IDE中显示源码,而不是JProfiler中的内置源码查看器。

IDE集成将在后面的章节中详细讨论。

Attach模式

对一个JVM进行分析,你不一定预先就做决定,通过JProfiler中的Attach功能,你可以选择一个正在运行的JVM,动态加载分析代理。 虽然Attach模式很方便,但它也有一些缺点你应该知道:

JProfiler启动中心的快速Attach选项卡列出了所有可以被分析的JVM。 列表项的背景颜色指示了是否已经加载了分析代理,当前是否连接了JProfiler GUI,或者是否已经配置了离线分析。

当你启动分析会话时,可以在会话设置对话框中配置分析设置。 当重复分析同一进程时,你不会希望重复输入相同的配置,所以当关闭用快速Attach功能创建的会话时,可以保存一个持久会话。 你下次要分析该进程时,从打开会话选项卡启动保存的会话而不是快速Attach选项卡。你仍然必须选择一个正在运行的JVM,但分析设置与你之前已经配置的相同。

Attach到本地服务

JVM中的Attach API要求调用进程与你想要Attach的进程以相同用户身份运行,所以JProfiler显示的JVM列表仅限于当前用户。 不同用户发起的进程大多是服务。对于Windows,Linux和基于Unix的平台,Attach到服务的方式有所不同。

在Windows上,Attach对话框有一个 显示服务按钮,会列出所有本地运行的服务。 JProfiler会启动桥接可执行文件,以便能够Attach到这些进程上,无论它们通过什么用户运行。

在Linux上,JProfiler支持通过PolicyKit在UI中直接切换用户,PolicyKit是大多数Linux发行版本的一部分。 通过点击attach对话框中的切换用户,你可以输入不同的用户名并通过系统密码对话框进行认证。

在基于Unix的平台上,包括macOS,你可以使用susudo 以不同用户身份执行命令行工具jpenable,这取决于你的Unix变种或Linux发行版。 macOS和基于Debian的Linux发行版(如Ubuntu)上,使用sudo

使用sudo,调用

sudo -u userName jpenable
使用su,所需的命令行是
su userName -c jpenable

jpenable 会让你选择 JVM,并告诉你分析代理正在监听的端口。 然后在启动中心的快速Attach选项卡上,你可以选择选项在另一台计算机上, 并配置一个直接连接到localhost和给定的分析端口。

Attach到远程机器上的JVM

分析最苛刻的设置是远程分析--JProfiler GUI在本地机器上运行,而分析的JVM在另一台机器上运行。 对于将-agentpath VM参数传递给分析的JVM的设置,你必须在远程机器上安装JProfiler,并在本地机器上设置一个远程会话。 有了JProfiler中的远程Attach功能,就不需要这样的修改,你只需要SSH凭证就可以登录到远程机器上。

SSH连接使JProfiler能够上传"安装JProfiler"帮助主题中讨论的代理包, 并在远程机器上执行包含的命令行工具。你不需要在你的本地机器上设置SSH,JProfiler有自己的实现。最简单的设置,你只需设置主机、用户名和认证。

通过SSH连接,JProfiler可以自动发现正在运行的JVM,或者连接到分析代理已经在监听的特定端口。对于后一种情况, 可以如上所述在远程机器上使用jpenablejpintegrate , 准备一个特别 JVM 以进行分析。然后,可以配置SSH远程Attach,直接连接到配置好的分析端口。

自动发现将列出远程机器上所有以SSH登录用户启动的JVM。在大多数情况下,这不是启动你想要分析的服务的用户。 因为启动服务的用户通常是不允许SSH连接的,所以JProfiler添加了切换用户超链接,让你使用sudosu 切换到那个用户。

在复杂的网络拓扑结构中,有时你不能直接连接到远程机器。在这种情况下,你可以告诉JProfiler在GUI中用一个多跳SSH隧道进行连接。 在SSH隧道的最后,你可以进行一个直接的网络连接,通常是"127.0.0.1"。

HPROF快照只能为以SSH登录用户启动的JVM生成。这是因为HPROF快照需要一个用启动JVM的用户访问权限写入的一个中间文件。 出于安全原因,不可能将文件权限转移给SSH登录用户进行下载。 对于完整的分析会话不存在这样的限制。

Attach到运行在Docker容器中的JVM

Docker容器通常没有安装SSH服务器,虽然你可以在Docker容器中使用jpenable, 但除非你在Docker文件中指定,否则分析端口将无法从外部访问。

在JProfiler中,你可以通过在快速Attach对话框中选择Docker容器,来Attach到,在Windows或macOS的本地Docker Desktop安装中运行的JVM。 在快速连接对话框中选择Docker容器。默认情况下,JProfiler会自动检测 docker可执行文件的路径。 另外,你也可以在常规设置对话框中的 "外部工具 "选项卡中配置。

在你选择容器后,所有在Docker容器内运行的JVM都会被显示出来。当你选择一个JVM时。 JProfiler将使用Docker命令在选定的容器中自动安装分析代理,为分析准备JVM,并将分析协议以隧道方式连接到外部。

对于远程Docker安装,你可以使用SSH远程Attach功能,然后在远程机器上选择一个Docker容器。 如果登录用户不在docker组中,你可以先按照上述方法切换用户。

通过远程Attach对话框中的选择容器超链接,你可以选择一个运行的Docker容器,并显示运行在其中的所有JVM。

Attach到运行在Kubernetes集群上的JVM

为了对运行在Kubernetes集群上的JVM进行分析,JProfiler使用kubectl命令行工具, 既可以发现pod和容器,也可以连接到容器,列出其JVM 并最终连接到选定的JVM。

kubectl命令行工具也许在你的本地计算机上可用,或者在一个你有SSH访问权远程机器上可用。 这两种情况JProfiler都支持。对于本地安装,JProfiler将自动尝试检测kubectl的路径, 但你可以在常规设置对话框中的”外部工具“选项卡配置一个明确的路径。

JProfiler会以一个三层树列出所有检测到的容器。最顶部是命名空间节点,其字节点包含检测到的pod。 叶节点是容器本身,必须选择其中之一以便进一步选择一个运行的JVM。

kubectl可能需要额外的命令行选项进行验证,以便能够连接到Kubernetes集群。 这些选项可以在容器选择对话框的顶部输入。因为这些选项可能是敏感信息,所以只有在你明确勾选要记住这些内容的,跨重启记住复选框, 这些信息才会被保存到磁盘。取消选择该复选框将立即清除任何先前保存的信息。

设置运行JVM的显示名称

在 JVM 选择表中,显示的进程名称是分析的 JVM 的主类及其参数。对于exe4j或install4j生成的启动程序,会显示可执行文件的名称。

如果您希望自己设置显示的名称,例如,因为您有几个具有相同主类的进程,否则将无法区分, 您可以设置VM参数-Djprofiler.displayName=[name] 。如果名称包含空格, 请使用单引号:-Djprofiler.displayName='My name with spaces' ,必要时用双引号引住整个VM参数。 除了-Djprofiler.displayName 外,JProfiler 还可以识别-Dvisualvm.display.name