JProfiler HelpDownload

Profiling A JVM


To profile a JVM, JProfiler's profiling agent has to be loaded into the JVM. This can happen in two different ways: By specifying an -agentpath VM parameter in the start script or by using the attach API to load the agent into an already running JVM.

JProfiler supports both modes. Adding the VM parameter is the preferred way to profile and is used by the integration wizards, the IDE plugins, and session configurations that launch a JVM from within JProfiler. Attaching works both locally as well as remotely over SSH.

-agentpath VM parameter

It is useful to understand how the VM parameter that loads the profiling agent is composed. -agentpath is a generic VM parameter provided by the JVM for loading any kind of native library that uses the JVMTI interface. Because the profiling interface JVMTI is a native interface, the profiling agent must be a native library. This means that you can only profile on the explicitly supported platforms. 32-bit and 64-bit JVMs also need different native libraries. Java agents, on the other hand, are loaded with the -javaagent VM parameter and only have access to a limited set of capabilities.

After -agentpath:, the full path name to the native library is appended. There is an equivalent parameter -agentlib: where you only specify the platform-specific library name, but then you have to make sure that the library is contained in the library path. After the path to the library, you can add an equals sign and pass options to the agent, separated by commas. For example, on Linux, the whole parameter could look like this:

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

The first equals sign separates the path name from the parameters, the second equals sign is part of the parameter port=8849. This common parameter defines the port on which the profiling agent is listening to connections from the JProfiler GUI. 8849 is actually the default port, so you can also omit that parameter. If you want to profile multiple JVMs on the same machine, you have to assign different ports, though. The IDE plugins and the locally launched sessions assign this port automatically, for integration wizards you have to choose the port explicitly.

The second parameter nowait tells the profiling agent not to block the JVM at startup and wait for a JProfiler GUI to connect. Blocking at startup is the default because the profiling agent does not receive its profiling settings as command line parameters but from the JProfiler GUI or alternatively from a config file. The command line parameters are only for bootstrapping the profiling agent, telling it how to get started and for passing debug flags.

Under some circumstances, setting the profiling settings at startup is required and some manual work may be required to achieve this.

By default, the JProfiler agent binds the communication socket to the loopback interface. You can add the option address=[IP address] in order to select a specific interface or address=0.0.0.0 to bind the communication socket to all available network interfaces. This can be necessary if you want to publish the profiling port from a docker container.

Locally launched sessions

Like "Run configurations" in an IDE, you can configure locally launched sessions directly in JProfiler. You specify the class path, the main class, working directory, VM parameters and arguments, and JProfiler launches the session for you. All the demo sessions that ship with JProfiler are locally launched sessions.

A special launch mode is "Web Start" where you select the URL of the JNLP file, and JProfiler will launch a JVM to profile it. This feature supports OpenWebStart, legacy WebStart from pre-Java 9 Oracle JREs is not supported.

Locally launched sessions can be converted to standalone sessions with the conversion wizards by invoking Session→Conversion Wizards from the main menu. Convert Application Session to Remote simply creates a start script and inserts the -agentpath VM parameter into the Java call. Convert Application Session to Offline creates a start script for offline profiling which means that the config is loaded on startup and the JProfiler GUI is not required. Convert Application Session to Redistributed Session does the same thing, but creates a directory jprofiler_redist next to it that contains the profiling agent as well as the config file so you can ship it to a different machine where JProfiler is not installed.

If you develop the profiled application yourself, consider using an IDE integration instead of a launched session. It will be more convenient and give you better source code navigation. If you do not develop the application yourself, but already have a start script, consider using the remote integration wizard. It will tell you the exact VM parameter that you have to add to the Java invocation.

Integration wizards

JProfiler's integration wizards handle many well-known third party containers with start scripts or config files that can be modified programmatically to include additional VM parameters. For some products, start scripts can be generated where VM parameters are passed as arguments or via environment variables.

In all cases, you have to locate some specific file from the third-party product, so JProfiler has the necessary context to perform its modifications. Some generic wizards only give you instructions on what you have to do in order to enable profiling.

The first step in each integration wizard is the choice whether to profile on the local machine or on a remote machine. In the case of the local machine you have to provide less information, because JProfiler already knows the platform, where JProfiler is installed and where its config file is located.

An important decision is the "startup mode" that was discussed above. By default, the profiling settings are transmitted from the JProfiler UI at startup, but you can also tell the profiling agent to let the JVM start immediately. In the latter case, the profiling settings can be applied once the JProfiler GUI connects.

However, you can also specify a config file with the profiling settings, which is much more efficient. This is done on the Config synchronization step. The main problem in this case is that you have to synchronize the config file with the remote side each time you edit the profiling settings locally. The most elegant way is to connect to the remote machine via SSH on the Remote address step, then the config file can be transferred automatically via SSH.

At the end of the integration wizard, a session will be created that starts profiling and - in the non-generic cases - also starts the third party product, such as an application server.

External start scripts are handled by the Execute start script and Execute stop script options on the Application settings tab of the session configuration dialog and URLs can be shown by selecting the Open browser with URL check box. This is also the place where you can change the address of the remote machine and the config synchronization options.

The integration wizards all handle cases where the profiled JVM is running on a remote machine. However, when a config file or start script has to be modified, you have to copy it to your local machine and transfer modified versions back to the remote machine. It may be more convenient to directly run the command line tool jpintegrate on the remote machine and let it perform its modifications in place. jpintegrate requires a full installation of JProfiler and has the same JRE requirements as the JProfiler GUI.

When an error occurs while starting a remote profiling session, see the trouble-shooting guide for a checklist of steps that you can take to fix the problem.

IDE integrations

The most convenient way to profile an application is through an IDE integration. If you usually start your application from your IDE during development, the IDE already has all the required information and the JProfiler plugin can simply add the VM parameter for profiling, start JProfiler if necessary and connect the profiled JVM to a JProfiler main window.

All IDE integrations are contained in the integrations directory in the JProfiler installation. In principle, the archives in that directory can be installed manually with the plugin installation mechanisms in the respective IDEs. However, the preferred way to install IDE integrations is to invoke Session→IDE integrations from the main menu.

Profiling sessions from the IDE do not get their own session entry in JProfiler, because such a session could not be started from the JProfiler GUI. Profiling settings are persisted on a per-project or a per-run-configuration basis, depending on the settings in the IDE.

When connected to an IDE, JProfiler shows a window switcher in the tool bar that makes it easy to jump back to the associated window in the IDE. All the Show Source actions now show the source directly in the IDE instead of the built-in source viewer in JProfiler.

IDE integrations are discussed in detail in a later chapter.

Attach mode

You do not necessarily have to decide beforehand that you intend to profile a JVM. With the attach functionality in JProfiler, you can select a running JVM and load the profiling agent on the fly. While attach mode is convenient, it has a couple of drawbacks that you should be aware of:

  • You have to identify the JVM that you want to profile from a list of running JVMs. This can sometimes be tricky if a lot of JVMs are running on the same machine.
  • There is additional overhead because potentially many classes have to be redefined to add instrumentation.
  • Some features in JProfiler are not available in attach mode. This is mostly because some capabilities of the JVMTI can only be switched on when the JVM is being initialized and are not available in later phases of the JVM's lifecycle.
  • Some features require instrumentation in a large fraction of all classes. Instrumenting while a class is being loaded is cheap, adding instrumentation later on when the class has already been loaded is not. Such features are disabled by default when you use attach mode.
  • Attach functionality is supported for OpenJDK JVMs, Oracle JVMs with version 6 or higher, recent OpenJ9 JVMs (8u281+, 11.0.11+ or Java 17+) or IBM JVMs that are based on such a release. The VM parameters -XX:+PerfDisableSharedMem and -XX:+DisableAttachMechanism must not be specified for the JVM.

The Quick Attach tab in JProfiler's start center lists all JVMs that can be profiled. The background color of the list entries indicates whether a profiling agent has already been loaded, whether a JProfiler GUI is currently connected or if offline profiling has been configured.

When you start a profiling session, you can configure profiling settings in the session settings dialog. When you repeatedly profile the same process, you do not want to re-enter the same configuration again and again, so a persistent session can be saved when you close a session that has been created with the quick attach feature. The next time you want to profile this process, start the saved session from the Open Session tab instead of the Quick Attach tab. You will still have to select a running JVM, but the profiling settings are the same ones that you have already configured before.

Attaching to local services

The attach API in the JVM requires that the invoking process runs as the same user as the process that you want to attach to, so the list of JVMs that are displayed by JProfiler is limited to the current user. Processes launched by different users are mostly services. The way to attach to services differs for Windows, Linux and Unix-based platforms.

On Windows, the attach dialog has a Show Services button that lists all locally running services. JProfiler launches bridge executables to be able to attach to those processes no matter what user they are running with.

On Linux, JProfiler supports switching the user directly in the UI through PolicyKit that is part of most Linux distributions. By clicking Switch user in the attach dialog, you can enter a different user name and authenticate with the system password dialog.

On Unix-based platforms including macOS, you can execute the command line tool jpenable as a different user with su or sudo, depending on your Unix variant or Linux distribution. On macOS and Debian-based Linux distributions like Ubuntu, sudo is used.

With sudo, call

sudo -u userName jpenable
with su, the required command line is
su userName -c jpenable

jpenable will let you select JVMs and tell you the port on which the profiling agent is listening. After that you can either connect with a local session from the JProfiler UI or an SSH connection that directly connects the port given by jpenable.

Attaching to JVMs on remote machines

The most demanding setup for profiling is remote profiling - the JProfiler GUI runs on your local machine and the profiled JVM on another machine. For a setup where you pass the -agentpath VM parameter to the profiled JVM, you have to install JProfiler on the remote machine and set up a remote session on your local machine. With the remote attach functionality in JProfiler, no such modifications are required. You just need SSH credentials to log into the remote machine.

The SSH connection enables JProfiler to upload the agent package that was discussed in the "Installing JProfiler" help topic and execute the contained command line tools on the remote machine. You don't need SSH to be set up on your local machine, JProfiler ships with its own implementation. In the most straightforward setup you just define host, user name and authentication.

With an SSH connection, JProfiler can perform an automatic discovery of running JVMs or connect to a specific port on which a profiling agent is already listening. For the latter case, you can use jpenable or jpintegrate on the remote machine as described above and prepare a special JVM for profiling. Then, the SSH remote attach can be configured to directly connect to the configured profiling port.

Automatic discovery will list all JVMs on the remote machine that have been started as the SSH login user. In most cases, this will not be the user that has started the service that you would like to profile. Because users that start services usually are not allowed for SSH connections, JProfiler adds a Switch User hyperlink that lets you use sudo or su to switch to that user.

In complex network topologies, you sometimes cannot connect directly to the remote machine. In that case, you can tell JProfiler to connect with a multi-hop SSH tunnel in the GUI. At the end of the SSH tunnel you can make one direct network connection, usually to "127.0.0.1".

HPROF snapshots can only be taken for JVMs that were started with the SSH login user. This is because HPROF snapshots require an intermediate file that is written with the access rights of the user that has started the JVM. For security reasons, it is not possible to transfer file rights to the SSH login user for download. No such restriction exists for full profiling sessions.

Attaching to JVMs running in Docker containers

Docker containers usually do not have SSH servers installed, and while you can use jpenable in a Docker container, the profiling port will not be accessible from the outside unless you have specified it in your Docker file.

In JProfiler, you can attach to a JVM running in a local Docker Desktop installation in Windows or macOS by selecting the Docker container in the quick attach dialog. By default, JProfiler detects the path to the docker executable automatically. Alternatively, you can configure it on the "External tools" tab of the general settings dialog.

After you select the container, all JVMs that run inside the Docker container will be shown. When you select a JVM, JProfiler will use Docker commands to automatically install the profiling agent in the selected container, prepare the JVM for profiling and tunnel the profiling protocol to the outside.

For remote Docker installations, you can use the SSH remote attach functionality and then select a Docker container on the remote machine. If the login user is not in the docker group, you can first switch the user as described above.

With the Select container hyperlink in the remote attach dialog you can choose a running Docker container and show all JVMs that are running in it.

Attaching to JVMs running on Kubernetes clusters

To profile a JVM that is running on a Kubernetes cluster, JProfiler uses the kubectl command line tool, both for discovering pods and containers, as well as to connect to a container, list its JVMs and finally to connect to a selected JVM.

The kubectl command line tool may be available on your local computer or alternatively on a remote machine to which you have SSH access. JProfiler directly supports both scenarios. For local installations, JProfiler will try to detect the path to kubectl automatically, but you can configure an explicit path on the "External tools" tab of the general settings dialog.

JProfiler lists all detected containers in a tree with three levels. At the top are namespace nodes that contain child nodes with the detected pods. The leaf nodes are the containers themselves and one of them has to be chosen to proceed to the selection of a running JVM .

kubectl may require additional command line options for authentication in order to be able to connect to the Kubernetes cluster. These options can be entered at the top of the container selection dialog. Because these options may be sensitive information, they are only saved to disk if you explicitly select the checkbox to remember them across restarts. Deselecting this checkbox will clear any previously saved information immediately.

Setting the display name of running JVMs

In the JVM selection table, the displayed process name is the main class of the profiled JVM together with its arguments. For launchers generated by exe4j or install4j, the executable name is displayed.

If you wish to set the displayed name yourself, for example, because you have several processes with the same main class that would otherwise be undistinguishable, you can set the VM parameter -Djprofiler.displayName=[name]. If the name contains spaces, use single quotes: -Djprofiler.displayName='My name with spaces' and quote the entire VM parameter with double quotes if necessary. In addition to -Djprofiler.displayName JProfiler also recognizes -Dvisualvm.display.name.