YourKit
YourKit Java Profiler 8.0 Offline Help

1 Getting started

 

1.1 Running profiler

To launch profiler UI:

Windows: launch "YourKit Java Profiler" from in the Start menu

Linux, Solaris: run <Profiler Installation Directory>/bin/yjp.sh

Although you can profile applications running on Java 5 and 6, the profiler UI itself requires Java 6 or newer to run. It can be downloaded from http://www.oracle.com/technetwork/java/javase/downloads/index.html

FreeBSD: run <Profiler Installation Directory>/bin/yjp.sh

To run the profiler UI as well as to run profiled applications, use Diablo Caffe JDK 1.6.0-7 or newer.

Mac OS X: after the downloaded application is unzipped, simply click its icon.

The profiler UI requires that there is Java 5 installed.

 

1.2 Running applications with profiler

You can profile any Java application that runs virtual machines from the following vendors:

  • Sun Java 5 and 6
  • JRockit 5 and 6 (R27.2.0 or newer)
  • IBM Java 5 (SR1 or newer)
  • IBM Java 6 (SR3 or newer)

For Java 7 support, use the latest version of the profiler.

For detail, see supported Java versions matrix.

Profiling is supported on following platforms:

  • Windows XP/Server 2003/Vista/Server 2008/7/Server 2008 R2, 32-bit Java (x86) and 64-bit Java (x86-64)
  • Linux, 32-bit Java (x86) and 64-bit Java (x86-64)
  • Mac OS X 10.4 and newer, PPC and Intel, 32-bit and 64-bit Java
  • Solaris 9 and newer, SPARC, 32-bit and 64-bit Java
  • Solaris 10 and newer, x86, 32-bit and 64-bit Java
  • FreeBSD 7 i386 and amd64 (aka x86-64) with Diablo Caffe JDK 1.6.0-7. Important! FreeBSD CPU profiling limitations: FreeBSD does not provide means to obtain CPU time spent in certain thread, but only in entire process. Due to this, ALL times measured by means of CPU profiling will look like wall times, disregarding your wall vs. CPU time settings in "Settings | Wall Time Methods...". Also, thread CPU time will be same for all threads in thread telemetry.

Profiling can be done locally (profiler and profiled application run on same machine) or remotely (profiled application runs on another computer accessible by network).

Please choose appropriate subtopic that corresponds to your type of applications

 

1.2.1 Profiling J2SE applications

There are different ways to profile your application.

  • With the help of IDE integration: use the "Profile" action from within your IDE, like you do "Run" or "Debug".

  • To launch a profiling-enabled application from outside the IDE, perform a few simple steps described in Enabling profiling manually.

 

1.2.2 Profiling J2EE applications

There are different ways to profile your application.

IDE integration

With the help of IDE integration: use the "Profile" action from within your IDE, like you do "Run" or "Debug".

J2EE server integration wizard

Automatically enable profiling in a number of popular application servers, generating appropriate startup scripts.

Manual configuration

If none of the above approaches apply, perform a few simple steps described in Enabling profiling manually for your application server.

Also see J2EE high-level profiling

 

1.2.3 Profiling remote J2EE applications

The following describes profiling of a J2EE server running on a remote machine (i.e. the server and the profiler UI run on different machines).

Read about profiling a local J2EE server (i.e. running on the same machine where you run the profiler UI) here.

If you have only a console access (e.g. via telnet, ssh etc.) to the machine where the J2EE server to be profiled is hosted, use the console version of the J2EE integration wizard. The wizard automatically enables profiling in a number of popular application servers, generating appropriate startup scripts.

  • Download Solaris ZIP archive distribution bundle. The Solaris ZIP archive is actually a multi-platform bundle containing all necessary files for each supported platform, thus do not hesitate using it on Windows, Linux, FreeBSD, Mac OS X.
  • Copy the ZIP file to the remote machine and unpack to arbitrary directory. License key is NOT required to run the console version of the integration wizard. Just copy the ZIP and unpack it.
  • Run this command and follow instructions that appear:
    java -jar <directory with unpacked content>/lib/yjp.jar -integrate

    You need Java 5 or newer to run the command.

Note: the integration wizard generates output files (copies of configuration files, additional startup scripts) in directories where original files locate. Please ensure that you run the command with sufficient access rights.

Also see J2EE high-level profiling

 

1.2.4 Profiling applets

  • With the help of IDE integration: use the "Profile" action from within your IDE, like you do "Run" or "Debug".

  • You can profile applets running inside a browser with Java Plugin installed.

    Please add -agentpath:<agent library path> option (see detail in Enabling profiling manually) in "Java(TM) Plug-in Control Panel", on the "Advanced" tab, in the field "Java Runtime Parameters".

    On Windows, "Java(TM) Plug-in Control Panel" is accessible from the Windows "Control Panel"

    Important: If the browser is running, you must restart it after you have made the changes.

  • You can profile applets started with appletviewer command by passing -J-agentpath:<agent library path> (see Enabling profiling manually) as a command line parameter.

 

1.2.5 Startup options

What are the startup options?

The startup options allow to customize some aspects of profiling. These options can be configured when you start the profiled application.

When should I specify the startup options?

In most cases, you do not have to specify any of these options, because default behavior suits fine in most cases.

How can I specify the startup options?

These options can be configured when you start the profiled application:

The options are comma-separated if you specify more than one option.

Description of the startup options


Main options

These options can be switched on startup only, i.e. corresponding behavior cannot be altered during runtime.
port=<value>

Specify the port that the profiler agent listens on for communication with the Profiler.

By default, the port is chosen automatically: if port 10001 is free, it is used; otherwise, if port 10002 is free, it is used etc.; if no port in the range 10001..10010 is free, an arbitrary free port is used.

listen=<ip>:<port>

Same as 'port' but this binds agent socket to a particular IP only

onlylocal

Allow only local connections to profiled application

dir=<directory for snapshots>

Specify the directory where snapshots are created. By default, <user home>/Snapshots directory is used.

delay=<time in milliseconds>

Postpone start of telemetry collection. This option is mostly intended to prevent startup issues of some J2EE servers.

By default, light-weight telemetry is collected right from the start of the profiled application.

The telemetry is collected via so called platform MBeans ("managed beans") - the components for monitoring and managing the JVM. Some J2EE servers install their own implementations of standard MBeans. In earliest stages of the server startup the MBeans can not be functional because they depend on other components of the server (such as custom logging) which have not initialized so far. Accessing such MBeans in earliest stages can cause the server startup failure (e.g. with ClassNotFoundException).

The "delay" option ensures that all MBeans are completely initialized before they are first accessed, by postponing the start of collecting the telemetry.

The J2EE integration wizard by default uses "delay=10000" to postpone the telemetry for 10 seconds. Although not all servers (and not all versions of particular server) suffer from the problem with MBeans, it is recommended to always use "delay" profiling a J2EE server to ensure that any J2EE server can successfully start. Furthermore, the telemetry of first few seconds of the server startup is unlikely of any interest for you, because the server's internals are being initialized during that time rather than your own application code.

If the 10 seconds delay is not enough in your particular case, try a bigger value.

telemetrylimit=<hours>

The telemetry information is remembered inside the profiler agent. This allows to connect to profiled application on demand, being able to discover how the application has behaved in the past.

By default, the telemetry buffer is limited to store approximately 1 hour of recent telemetry data.

With the help of the telemetrylimit option you can customize the time period within which the telemetry data is being stored.

Do not use unnecessarily long buffers

Extending the telemetry buffer will allocate additional amount of memory in the profiled application's address space. That is especially important for 32-bit JVMs configured to use big heap (-Xmx) because total process memory is limited to 2-4 GB (depends on OS) and JVM failure may happen if enough memory is not available outside the heap space.

Also, the longer the buffer, the more time it takes to retrieve the telemetry information from the profiler agent when you connect to a long running profiled application.

The limit is not exact

It is not guaranteed that data will be kept within exactly specified hours. hours is rather an approximation; the actual time may slightly (+/- 5 minutes) differ to ensure best performance.

onexit=memory

Always capture a memory snapshot on exit. CPU snapshot will be captured automatically if CPU profiling is enabled when the profiled application exits.

onexit=snapshot

Capture recorded data (telemetry, and if recorded CPU and monitors profiling results) on exit. This option is automatically used when the profiled application is started from the IDE.

quiet

Suppress diagnostics messages that the profiler agent prints to the console.


Control which profiling modes are turned on right from the start

Note that you do not have to perform measuring right from the start. Instead, in many cases it's better to start or stop measuring at a later moment - from the UI or by using the Profiler API.
sampling

Launch Java application with CPU sampling turned on. Note that you do not have to profile CPU right from the start; instead, in many cases it's better to start or stop measuring at a later moment - from the UI or by using the Profiler API.

tracing

Launch Java application with CPU tracing turned on. Note that you do not have to profile CPU right from the start; instead, in many cases it's better to start or stop measuring at a later moment - from the UI or by using the Profiler API. This option cannot be used in combination with 'disablecounts'.

noj2ee

Do not perform J2EE high level profiling. This option influences only CPU profiling started with 'sampling' or 'tracing'. Read more about CPU profiling modes.

alloc

Launch Java application with object allocation recording started. All objects will be recorded. Note that you do not have to record allocations right from the start; instead, you can start or stop recording later from the Profiler or using Profiler API. This option cannot be used in combination with 'disablealloc'.

alloceach=<N>

Launch Java application with object allocation recording started and record each N-th allocation. This option can be used in combination with 'allocsizelimit'. This option cannot be used in combination with 'disablealloc'.

Note that you do not have to record allocations right from the start; instead, you can start or stop recording later from the Profiler or using Profiler API.

allocsizelimit=<B>

Launch Java application with object allocation recording started and record allocation of objects with size bigger or equal B bytes. This option can be used in combination with 'alloceach'. This option cannot be used in combination with 'disablealloc'.

Note that you do not have to record allocations right from the start; instead, you can start or stop recording later from the Profiler or using Profiler API.

monitors

Launch Java application with started monitor profiling. Note that you do not have to profile monitor usage right from the start; instead, you can start or stop recording later from the Profiler or using Profiler API.

usedmem=<percent>

Automatically capture a memory snapshot when used heap memory reaches the threshold.

disablestacktelemetry

Do not collect thread stack and status information shown in Thread view as well as in other telemetry views. This information can be very useful because it allows you to connect to the profiled application on demand and discover how the application behaved in the past. In most cases, there is no significant overhead of collecting this information. However, it makes sense to disable it in production J2EE servers in order to ensure minimum profiling overhead. See also: Profiling overhead: how to reduce or avoid.

disableexceptiontelemetry

Do not collect exception telemetry. The exception telemetry helps discovering performance issues and logic errors. In most cases, there is no significant overhead of collecting this information. However, it makes sense to disable it in production J2EE servers in order to ensure minimum profiling overhead. See also: Profiling overhead: how to reduce or avoid.


Optimization options

Reduce profiling overhead by disabling some profiling capabilities.
See also: Profiling overhead: how to reduce or avoid.

These options can be switched on startup only, i.e. corresponding behavior cannot be altered during runtime.
disablealloc

Do not instrument bytecode with instructions needed for object allocation recording. See also: Profiling overhead: how to reduce or avoid.

disablecounts

Do not instrument bytecode with instructions needed for CPU tracing. Only CPU sampling will be available. See also: Profiling overhead: how to reduce or avoid.

disablej2ee

Do not instrument bytecode with instructions needed for J2EE profiling. See also: Profiling overhead: how to reduce or avoid.

disableall

Disable several capabilities at once: disablealloc, disablecounts, disablej2ee, disableexceptiontelemetry, disablestacktelemetry


Miscellaneous
help

Print brief description of startup options.


 

1.2.6 Profiling overhead: how to reduce or avoid

The profiler may add some overhead to the performance of applications you profile. This overhead may vary from virtually zero to significant, depending on the conditions described below.

Overhead of running an application with profiler

To enable such features as recording object allocation and CPU tracing, the profiler inserts some supporting code into the bytecode of the profiled application by means of bytecode instrumentation. When allocation recording and CPU tracing are not performed, this inserted code is in inactive state but still adds a small overhead to the performance of instrumented methods (1-5%, depending on the application). The process of bytecode instrumentation itself, of course, also requires some fixed time that depends on the number of loaded classes and their methods.

In most cases, such overhead is more than acceptable.

For cases when maximum performance is needed, e.g. if profiling in production, this overhead can be totally eliminated by avoiding bytecode instrumentation. The price you pay is that some features are disabled. But even when they are disabled, you can still capture memory snapshots and perform CPU sampling, which is enough in many cases (see Solving performance problems).

You can disable bytecode instrumentation by specifying "disablecounts", "disablealloc" and "disablej2ee" startup options.

Since the greatest share of the overhead described above is caused by instrumentation needed for tracing, as a compromise you can disable this feature alone, keeping the ability to record object allocations on demand.

There is another, almost negligible, issue: if Java 5 or 6 JVM loads an agent that is capable of profiling heap memory, JVM class data sharing is disabled. This may slightly increase startup time, i.e. the time the JVM needs to load its core classes from rt.jar. For details about class sharing, refer to this page on the Sun website: http://java.sun.com/j2se/1.5.0/docs/guide/vm/class-data-sharing.html

Overhead when measuring is performed

When CPU profiling and/or allocation recording are performed, the profiler adds extra overhead. After measuring is done and turned off, overhead should decrease to the level described above in "Overhead of running an application with profiler".

Snapshot capture

During the capture, the profiled application is paused. The time it takes to capture a memory snapshot depends on the heap size. Capturing memory snapshots of huge heaps takes more time because of the intensive use of the system swap file (if little free physical memory is available).

Thread stack and status telemetry

Thread stack and status information is shown in Thread view as well as in other telemetry views. This information can be very useful because it allows you to connect to the profiled application on demand and discover how the application behaved in the past. In most cases, there is no significant overhead of collecting this information.

However, it makes sense to disable it in production J2EE servers in order to ensure minimum profiling overhead. This can be done with the help of "disablestacktelemetry" startup option.

Exception telemetry

Exception telemetry helps discovering performance issues and logic errors. In most cases, there is no significant overhead of collecting this information.

However, it makes sense to disable it in production J2EE servers in order to ensure minimum profiling overhead. This can be done with the help of "disablestacktelemetry" startup option.

 

1.2.7 Enabling profiling manually

Most likely, you will not need to configure profiling manually. Please first consider the automated ways to enable profiling in your J2SE, J2EE application or applet.

Step 1: Make profiler agent library accessible to the Java Virtual Machine

The action depends on your OS:

Windows, 32-bit Java

add <Profiler Directory>\bin\win32 to the PATH

Windows, 64-bit Java

add <Profiler Directory>\bin\win64 to the PATH

Mac OS X

add <Profiler Directory>/bin/mac to the DYLD_LIBRARY_PATH

Linux x86, 32-bit Java

add <Profiler Directory>/bin/linux-x86-32 to the LD_LIBRARY_PATH

Linux x86, 64-bit Java

add <Profiler Directory>/bin/linux-x86-64 to the LD_LIBRARY_PATH

Solaris SPARC, 32-bit Java

add <Profiler Directory>/bin/solaris-sparc-32 to the LD_LIBRARY_PATH

Solaris SPARC, 64-bit Java

add <Profiler Directory>/bin/solaris-sparc-64 to the LD_LIBRARY_PATH

Solaris x86, 32-bit Java

add <Profiler Directory>/bin/solaris-x86-32 to the LD_LIBRARY_PATH

Solaris x86, 64-bit Java

add <Profiler Directory>/bin/solaris-x86-64 to the LD_LIBRARY_PATH

You can find examples of startup scripts for your platform in <Profiler Directory>/samples

To make sure that Java can load the profiler agent, you can invoke the following command that prints a description of agent parameters:

java -agentlib:yjpagent=help

Step 2: Add -agentlib:yjpagent VM parameter to the command line of Java application

E.g., java -agentlib:yjpagent FooClass

Startup options

-agentlib:yjpagent provides additional startup options. In most cases there's no need to use them.

To profile a J2EE server (especially JBoss!), specify startup option delay=10000

The options are comma separated: -agentlib:yjpagent[=<option>, ...].

Please find detailed description of the startup options here.

Examples:

java -agentlib:yjpagent FooClass
java -agentlib:yjpagent=onexit=snapshot,dir=c:\MySnapshots FooClass
java -agentlib:yjpagent=usedmem=70 FooClass

Instead of -agentlib:yjpagent, you can specify -agentpath:<full agent library path>. The benefit is that you do not have to alter PATH/LD_LIBRARY_PATH/DYLD_LIBRARY_PATH:

Windows, 32-bit Java:
-agentpath:<Profiler Directory>\bin\win32\yjpagent.dll

Windows, 64-bit Java:
-agentpath:<Profiler Directory>\bin\win64\yjpagent.dll

Linux, 32-bit Java:
-agentpath:<Profiler Directory>/bin/linux-x86-32/libyjpagent.so

Linux, 64-bit Java:
-agentpath:<Profiler Directory>/bin/linux-x86-64/libyjpagent.so

Solaris SPARC, 32-bit Java:
-agentpath:<Profiler Directory>/bin/solaris-sparc-32/libyjpagent.so

Solaris SPARC, 64-bit Java:
-agentpath:<Profiler Directory>/bin/solaris-sparc-64/libyjpagent.so

Solaris x86, 32-bit Java:
-agentpath:<Profiler Directory>/bin/solaris-x86-32/libyjpagent.so

Solaris x86, 64-bit Java:
-agentpath:<Profiler Directory>/bin/solaris-x86-64/libyjpagent.so

Mac OS X:
-agentpath:<Profiler Directory>/bin/mac/libyjpagent.jnilib

 

1.2.8 About JVMTI (advanced topic)

This is an advanced topic. It provides details that you do not normally have to know to profile your applications. Read the following if you want to learn more about profiling capabilities provided by different versions of Java.

What a Java profiling API is

Any profiler, in order to provide profiling results, communicates with JVM by means of a special API. This API provides different services and influences the range of a profiler's capabilities.

JVMTI, the new standard API (Java 5 and newer)

Starting with Java 5, a new standardized API was introduced - JVMTI (http://java.sun.com/j2se/1.5.0/docs/guide/jvmti/index.html). It had replaced JVMPI API used in previous Java versions.

JVMTI utilizes so-called "bytecode instrumentation". This means that profilers, in order to collect profiling information, should modify the bytecode of profiled application, inserting at certain points some supporting bytecode instructions. There may be some performance issues because of this.

The implementation of JVMTI in Java 5 has several drawbacks (they have been solved in Java 6):

  • parallel garbage collector is not supported (-XX:+UseConcMarkSweepGC, -Xincgc)
  • there is no reasonably fast way to retrieve exact lengths of arrays when capturing a memory snapshot

 

2 Solving performance problems

What performance problems may arise?

  • Application algorithms are usually not optimal, which leads to performance bottlenecks.
  • For memory-related issues see below.

Why memory-related issues can cause performance problems?

Memory-related issues can affect an application's execution speed and stability:

  • When Java Virtual Machine cannot allocate an object (because it is out of memory, and no more memory can be freed by the garbage collector), OutOfMemoryError is thrown, which can cause an application crash or further unstable operation.
  • An application that uses a lot of memory reduces available physical memory for itself and other programs, and thus forces the operating system to swap memory pages to and from the disk more frequently. This leads to serious overall system performance degradation.
  • Java Virtual Machine spends more time to perform garbage collection when more objects exist and more temporary objects are created.

Read more about memory-related problems:

 

2.1 Performance bottlenecks

How to find a performance bottleneck using CPU profiling?

Let us assume there is a task in your application that you want to profile.

Read more about CPU profiling

 

2.2 Optimizing memory usage

How to find out why application eats that much memory?

 

2.3 Memory leaks

What is a memory leak?

Memory leak is an existence of objects that are not needed anymore according to the application logic, but still retain memory and cannot be collected because they are referenced from other live objects, due to a bug in application itself.
Obviously, each leaked object is accessible from at least one GC root or represents a GC root. In other words, for each leaked object there is always a path that starts from GC root(s) and contains (ends with) the leaked object.

How to find memory leaks?

1. Detect memory leak, i.e. understand what objects do exist while they should not.

If you do not know yet what objects are leaked, YourKit Java Profiler can help you find out.

You can suspect the presence of memory leaks with the help of Telemetry, by watching how used memory grows in the "Memory" tab. You can use "Force Garbage Collection" to see whether some of the objects that consume the memory can be collected, thus decreasing used memory. If after those explicit garbage collections the used memory remains on the same level or decreases insignificantly, this possibly means you have a leak. ("Possibly," because it can turn out not to be a leak, but simply high memory consumption -- Learn how to deal with that case)

Also consider the capture snapshot on low memory feature. Snapshots captured automatically using this feature may possibly be captured in the state when memory usage reaches the specified threshold because of memory leaks. Thus, the snapshots will provide information sufficient to discover and fix the leaks.

To detect a memory leak, use the following scenario:

  • Connect to profiled application
  • Advance generation number just before executing the task which is suspected to cause leak.
  • Let the application perform the task.
  • Capture memory snapshot and open it.
  • Use the "Generations" view to see objects created during the task execution; leaked objects should be among them.

You can also analyze a single snapshot, with the help of Statistics section in the "All Objects" view.

Often, potential leaks in particular profiled application are well known in advance, i.e. you know a class of objects that have a "tendency" to leak while application is being developed, changed, refactored. You can easily check for the presence of such objects, with the help of Memory | Instances by Class... (Ctrl+N). In more complex cases, you can use Set description language to declare sets of potentially leaked objects.

Note that even one class can have objects legally and illegally (leaked objects) retained in memory. To distinguish between them, you can use objects explorer to see outgoing and/or incoming references. For example, an object may have a String field with the value that can identify this object among other objects of the same type.

2. Once you have found leaked object(s), it's time to understand why they are retained in memory

Select the leaked object(s) in a memory view, and use Memory | Paths from GC Roots... (Ctrl+P). See Working with paths for details.

Let us look at a simple example of how to use paths.

    Assume that we are profiling an Editor application that can open, edit and close text files. There is a singleton object that acts as a manager of opened files, and the data of each opened file is represented with an instance of class Document.

    During the profiling session we open several text files, edit them, close them and take a memory snapshot.

    If everything is correct, there should be no instances of Document that cannot be collected. So, first of all, we use Memory | Instances by Class... (Ctrl+N), to see if there are leaked Documents.

    Assume we have found such objects - so we do have a leak. There should be paths from GC roots to these objects (or, perhaps, some of them may belong to GC roots themselves - this will be indicated in the view).

    Thus we search for the paths from GC roots to one of the Documents (Ctrl+P), or to all Documents defining the set.
    If all the paths go through the manager singleton, the code responsible for closing files in our editor must have a bug.
    If none of the paths contains the manager singleton, then the closing operation works correctly, but there are object(s) in the path(s) that erroneously hold references to Documents and cause the memory leak.

Browsing paths, use navigation feature of IDE integration.

 

2.3.1 GC roots

The so-called GC (Garbage Collector) roots are objects special for garbage collector. Garbage collector collects those objects that are not GC roots and are not accessible by references from GC roots.

There are several kinds of GC roots. One object can belong to more than one kind of root. The root kinds are:

  • Class - class loaded by system class loader. Such classes can never be unloaded. They can hold objects via static fields. Please note that classes loaded by custom class loaders are not roots, unless corresponding instances of java.lang.Class happen to be roots of other kind(s).
  • Thread - live thread
  • Stack Local - local variable or parameter of Java method
  • JNI Local - local variable or parameter of JNI method
  • JNI Global - global JNI reference
  • Monitor Used - objects used as a monitor for synchronization
  • Held by JVM - objects held from garbage collection by JVM for its purposes. Actually the list of such objects depends on JVM implementation. Possible known cases are: the system class loader, a few important exception classes which the JVM knows about, a few pre-allocated objects for exception handling, and custom class loaders when they are in the process of loading classes. Unfortunately, JVM provides absolutely no additional detail for such objects. Thus it is up to the analyst to decide to which case a certain "Held by JVM" belongs.

If an object is a root, it is specially marked in all views showing individual objects. For example, the following picture shows a fragment of paths view:

 

2.4 Excessive garbage allocation

How to find excessive garbage allocation?

Purpose: Reduce time that garbage collector spends on collecting temporary objects.

If garbage collection takes a significant amount of time, it is advised to profile memory allocation to pin-point and optimize the problematic code.

Let us assume there is a task in your application that you want to profile.

  • Start recording allocations (with default settings) right before the task is started.
  • Wait until the task finishes or performs long enough.
  • Capture memory snapshot and stop allocation recording.
  • Open snapshot and use Garbage Collection view.

Optionally, the profiled application can be launched with allocation recording started. Memory snapshot with recorded allocation information can be captured automatically on profiled application exit and/or on low memory. Read more in the Additional options section.

 

2.5 Out of memory error (OutOfMemoryError and -XX:+HeapDumpOnOutOfMemoryError)

A memory snapshot is captured automatically on first OutOfMemoryError, if the profiled application runs on Sun Java 6 or newer.

On OutOfMemoryError snapshots are captured via JVM's built-in dumper, which for some reason is off by default. The profiler agent turns it on upon profiled application startup. This adds absolutely no overhead. (Technically, enabling is simply setting the state of a boolean flag. When the first OutOfMemoryError occurs, the JVM dumps the heap to file if the flag is "true").

The corresponding JVM option -XX:+HeapDumpOnOutOfMemoryError is supported not only in Java 6 or newer, but also in Sun Java 1.4.2_12 and newer and in Sun Java 5.0 update 7 and newer. Unfortunately, only since Java 6 it is accessible programmatically. The only way to enable it in pre-Java 6 JVM is to explicitly specify -XX:+HeapDumpOnOutOfMemoryError in the command line of the profiled application.

To check the status, connect to the profiled application and hover over corresponding button as shown on the picture below:

The profiler shows the following notification when a snapshot is captured on OutOfMemoryError.

Please note that this approach has several benefits over the capturing snapshot on low memory feature, because it uses the JVM's internal light-weight dumping algorithm. This algorithm is specially designed to work in low memory conditions, where the JVM general purpose profiling interface JVMTI used by profilers may fail due to low resources.

See also Support of HPROF format snapshots.

 

3 Connect to profiled application

Once you have profiled application running, you should connect to it to obtain and analyze profiling results.

If you launch the profiled application from your IDE, the profiler UI will automatically start and connect to the application (unless you had turned this option off in the IDE).

To connect, use Welcome screen:

Connect to locally running profiled application

"Locally running profiled application" means that the profiled application is running on the same computer where you are now using the profiler UI.

The profiler can automatically detect all locally running profiled applications.

If more than one is found, you will be asked to select one. If only one application is found, the profiler will connect to it without prompting you.

Connect to remote application

Use this to connect to a profiled application that is running on a remote computer.

You can simply specify the host (name or IP address) of the remote computer where the profiled application(s) is (are) running. In this case the profiler tries to automatically detect the profiled applications on ports in some predefined range. When the profiled application starts, the profiler agent first tries to use a port in this range, thus enabling an automatic scan of the applications on remote host.

If you explicitly specified a port to be used by the profiler agent when launching the profiled application, you have to explicitly enter the port together with the host (using the syntax host:port). Automatic detection will not work in this case. Also, you should specify the pair host:port if there are so many profiled applications running simultaneously that for some of them there was no free port available in the predefined range.

In connected mode

After a connection is established successfully, the profiling session tab opens. It contains the toolbar to control profiling and displays application telemetry.

1. Capture Performance Snapshot - save the profiling results to a file, which can be opened later
2. CPU Profiling controls
3. Control thread telemetry
4. Memory Profiling controls
5. Force Garbage Collection
6. Monitor Profiling controls
7. Clear exception telemetry
8. "Pause" - stop/start receiving data from profiled application.
"Refresh" - immediately receive profiling data from the profiled application and update the views
9. Scale graphs

You can close the profiling session tab by selecting File | Close Profiling Session.

You can connect to and disconnect from the profiled application as many times as you wish during its run time.

 

4 CPU profiling

Get CPU usage overview with the help of the CPU telemetry.

For comprehensive analysis, record CPU information with the help of sampling or tracing.

 

4.1 CPU usage telemetry

The "CPU" tab shows live CPU consumption statistics when you are connected to the profiled application.

A very useful and unique feature of this graph is that the telemetry information is remembered inside the profiler agent. This allows you to connect to the profiled application on demand and discover how the application behaved in the past.

The CPU usage graph is stored in snapshots too:

 

4.2 Recording CPU information. Sampling and tracing.

First, connect to the profiled application.

CPU profiling controls in the toolbar

The toolbar contains the following CPU profiling controls:

CPU profiling

  • Start measuring

    To begin obtaining profiling results, start CPU measuring when your application requires it.

    You can choose either of two available measurement modes: sampling or tracing.

    Time

    Invocation Count

    Overhead

    Accuracy

    Sampling

    Available

    Not available

    Negligible

    Average

    Tracing

    Available

    Available

    Depends on filters

    High with proper filters

    Sampling

    When sampling is used, the profiler periodically queries stacks of running threads to estimate the slowest parts of the code. No method invocation counts are available, only CPU time.

    Sampling is typically the best option when your goal is to locate and discover performance bottlenecks. With sampling, the profiler adds virtually no overhead to the profiled application.

    Tracing

    When tracing is used, the profiler instruments the bytecode of the profiled application for recording thread CPU time spent inside each profiled method. Both times and invocation counts are available.

    Although tracing provides more information, it has its drawbacks. First, it may noticeably slow down the profiled application, because the profiler executes special code on each enter to and exit from the methods being profiled. The greater the number of method invocations in the profiled application, the lower its speed when tracing is turned on.

    The second drawback is that, since this mode affects the execution speed of the profiled application, the CPU times recorded in this mode may be less adequate than times recorded with sampling. Please use this mode only if you really need method invocation counts.

    Use filters to reduce overhead and increase accuracy of CPU tracing, by specifying which methods to profile.

    After selecting the profiling options, start profiling as follows:

  • Live results

    When profiling is started, the bottom table on the "CPU" tab shows a top-down call tree with calls with all threads merged.

    In case of CPU tracing, both method invocation counts and times are shown. Invocation counts are not cumulative. In case of CPU sampling, method times are shown.

    CPU telemetry provides only basic information. To perform comprehensive analysis, use "Capture performance snapshot".

  • Finish measuring and get the results

    When the task you intended to profile has finished (or has performed for a sufficient amount of time), capture a CPU snapshot with all the recorded information.

    When this is done from the profiler UI, you can open the results for immediate analysis.

    Further topics in this section describe the profiler's UI for analyzing CPU profiling results.

You can start and stop CPU profiling during the execution of your application as many times as you want. When CPU profiling is not running, YourKit Java Profiler adds no performance overhead to application being profiled.

Note: In some cases, it also may be useful to launch the application with CPU profiling already started and/or automatically capture CPU snapshot on exit of the profiled application (see Additional options).

CPU profiling can be performed programmatically with the help of the Profiler API

 

4.3 CPU view

CPU view (View | CPU) shows CPU consumption details.

The view consists of the following sections:

  • Call tree

    Shows a top-down call tree for each thread ("by thread")

    or with calls from all threads merged ("all threads together").

    The tree is shown based on current filters.

  • Hot spots

    Shows methods that consumed the most time.

    Methods are shown based on current filters:

    • non-filtered methods (typically, methods from the source code of profiled application)
    • filtered methods (typically, methods from core classes and used libraries) that were directly called from non-filtered methods or are at the top of thread stack trace (Thread.run()).

  • Method list

    Methods are shown based on current filters:

    • non-filtered methods (typically, methods from the source code of profiled application)
    • filtered methods (typically, methods from core classes and used libraries) that were directly called from non-filtered methods or are at the top of thread stack trace (Thread.run()).

    For each method, the list shows its time, its own time and, with CPU tracing, its invocation count.

    You can narrow down the list by typing a method name inside the text field.

Method invocation counts are available with CPU tracing. Invocation counts are not cumulative.

You can apply the following actions to the selected method (available from the popup menu as well):

 

4.4 Callees list view

"Callees list" view shows which methods were called from certain methods. It is available as a slave view.

  • In "Call tree (all threads together)":
  • In "Call tree (by thread)":
  • In "Hot spots":
  • In "Method list":

Callees list for "Call tree" shows methods invoked inside a selected subtree. When you view "Call tree (by thread)", callees list will show methods invoked in the subtree in particular thread only. To see all methods invoked in a thread, select the thread node.

Callees list for "Hot spots" and "Method list" shows methods invoked inside a selected method.

 

4.5 Method merged callees view

This view shows merged callees for a particular method, i.e. all call traces started from this method. This gives a summary of method execution and its "overall" behavior.

  • CPU | Method Merged Callees (Ctrl+M) opens this view for the selected method.

If method invocation counts were recorded, they are shown in call trees as well. Invocation counts are not cumulative.

You can apply the following actions to the selected method (available from the popup menu as well):

  • CPU | Method Merged Callees (Ctrl+M) - shows the method's merged callees.
  • CPU | Method Back Traces (Ctrl+Shift+M) - shows the method's back traces.
  • Tools | Open Declaration in IDE Editor (F7) - opens method declaration in IDE editor (see IDE integration).

 

4.6 Method back traces view

This view shows where a particular method was called.

  • CPU | Method Back Traces (Ctrl+Shift+M) opens this view for the selected method.

If method invocation counts were recorded, they are shown in call trees as well. Invocation counts are not cumulative.

You can apply the following actions to the selected method (also available from the popup menu):

  • CPU | Method Merged Callees (Ctrl+M) - shows the method's merged callees.
  • CPU | Method Back Traces (Ctrl+Shift+M) - shows the method's back traces.
  • Tools | Open Declaration in IDE Editor (F7) - opens method declaration in IDE editor (see IDE integration).

 

4.7 J2EE high-level profiling

YourKit Java Profiler provides a way to profile J2EE applications in high-level terms like SQL statements and URLs.

To get profiling results, make sure J2EE Profiling is enabled before starting CPU profiling:


After a CPU snapshot is captured, J2EE profiling results are available in the "J2EE Statistics" view:


The view consists of the following sections:

  • SQL

    Shows a list of SQL statements and back traces for all methods invoked with these statements

  • JSPs and Servlets

    Shows list a of URLs that correspond to JSP and Servlet calls, and merged callees for all methods invoked with these URLs

  • JNDI

    Shows list of URLs that correspond to JNDI calls, and back traces for all methods invoked with these URLs

For each J2EE call CPU time and invocation count are reported.

J2EE profiling requires bytecode instrumentation and adds some additional overhead to the profiled application. For detailed information, see Profiling overhead: how to reduce or avoid

Lines can be copied to clipboard by using File | Copy to Clipboard (Ctrl + C):

 

4.8 Comparing performance snapshots

You can compare two arbitrary snapshots that contain recorded CPU information, obtained with sampling or tracing.

To compare snapshots, do the following:

  • Open the snapshots you want to compare.
  • Select one of them.
  • Use File | Compare Snapshot with... (the action is also available from the popup menu) and select a snapshot to compare with.

The tab with "Comparison" view opens. It contains the following CPU views:

  • "Call tree" and "Method list" with 3 columns: Time Diff (ms), Old Time (ms), and New Time (ms), which display differences in method execution times.

  • If both snapshots contain invocation counts (i.e. results were gathered in Tracing mode) the views will have additional columns displaying the difference in method invocation counts.
 

5 Threads

When you are connected to the profiled application, use the "Threads" tab to track the live threads.

A very useful and unique feature of this graph is that the telemetry information is remembered inside the profiler agent. This allows you to connect to the profiled application on demand and discover how the application behaved in the past.

Please also consider the automatic deadlock detector

Disabling/enabling stack telemetry

The thread stack and state telemetry information can be very useful because it allows you to connect to the profiled application on demand and discover how the application behaved in the past. In most cases, there is no significant overhead of collecting this information, and thus you do not need to disable it.

However, it makes sense to disable it in production J2EE servers in order to ensure minimum profiling overhead.

The telemetry is enabled by default, unless "disablestacktelemetry" startup option was specified.

When you are connected to the profiled application, use corresponding toolbar button to enable/disable the telemetry:

 

6 Automatic deadlock detector

If a Java-level deadlock happens in the profiled application, it will be automatically detected.

When you are connected to the profiled application, switch to the "Deadlocks" tab.

If the deadlock is found, a notification will be shown. Find the deadlock detail in the "Deadlocks" tab.

 

7 Memory profiling

 

7.1 Memory telemetry

After you are connected to the profiled application, find the "Memory" telemetry tab on the session panel.

Memory profiling controls in the toolbar

Memory usage graphs

The "Memory" tab shows live memory usage statistics:

  • Heap memory usage (heap memory is the storage for Java objects)
  • Non heap memory usage (non heap memory is used by Java to store loaded classes and other meta-data)
  • Current class loading statistics


A very useful and unique feature of this graph is that the telemetry information is remembered inside the profiler agent. This allows you to connect to the profiled application on demand and discover how the application behaved in the past.

Class instance count telemetry

The bottom table on the "Memory" tab provides a quick overview of the current heap state. To perform comprehensive analysis capture a memory snapshot.

This information can be useful as an overview of memory consumed by the profiled application and also as a clue to detecting memory leaks. For details, see How to find out why application eats that much memory? and How to find memory leaks?

Allocation telemetry

You can profile object allocation without capturing a memory snapshot.

"Memory | Allocations" tab shows counts and sizes for objects whose allocations have been recorded, including objects which are still alive as well as objects that have been collected by the moment.

This live view provides only basic information, and you still need to capture memory snapshot to perform comprehensive analysis: to separate live objects from dead objects, to see where live objects are retained, etc.

 

7.2 Memory snapshot

A memory snapshot represents the memory state of the profiled application at the moment it was captured. It contains information about all loaded classes, about all existing objects, and about references between objects.

Snapshots can contain values of fields and arrays of primitive types (int, long, char etc.). Read more.

Optionally, snapshot can contain information about object allocations.

Note: If the profiled application ran on Java 5, recorded lengths of arrays are not exact, because of Java 5 JVMTI limitations. Instead they are estimated based on the size of the array as a whole and the size of one array element. The reason is that Java 5 provides no reasonably fast ways to get the exact values. This issue has been solved in Java 6 by extending JVMTI API with the appropriate means.

Inaccessible objects are treated as if they were already collected

When a snapshot is opened in the profiler, objects that are not referenced and thus can be collected are treated as collected. It is also assumed that all weak and soft references are nulled, and the objects accessible by only weak or soft references are treated as collected. This simplifies memory leak detection and helps you focus on the real, "hard referenced" problems.

In a very special case, you may want to keep weak/soft references. To achieve this, specify properties -Dyjp.keep.weak.refs=true and/or -Dyjp.keep.soft.refs=true in:

  • Windows: <Profiler Installation Directory>\bin\win32\yjp.ini
  • Linux, Solaris, FreeBSD: <Profiler Installation Directory>/bin/yjp.sh
  • Mac OS X: <Profiler Installation Directory>/Contents/Info.plist

Note: These are experimental options and may be dropped in future releases.

Note: Whenever you change properties yjp.keep.weak.refs and/or yjp.keep.soft.refs, delete or re-create snapshot index file if it was created for different settings; otherwise the change will take no effect.

Snapshot formats

You have an option to capture snapshot in YourKit Java Profiler format or via JVM built-in dumper:

Read more about HPROF snapshots.

 

7.3 Allocation recording

YourKit Java Profiler can optionally record object allocations, that is, track method call stacks where objects are created. Memory snapshots captured when allocations are being recorded contain allocation information. If an object was created when allocations were not being recorded, or recording was stopped at least once after the object had been created, snapshot will contain no allocation information for that object.

Recording of allocations adds performance overhead. This is the reason why allocations should not be recorded permanently. Instead, it is recommended to record allocations only when you really need them.

In order to keep moderate overhead, it is reasonable to skip allocation events for some percent of objects. This approach is useful to find the excessive garbage collection.

Also, you can record allocations for each object with size bigger than certain threshold. It is valuable to know where the biggest objects are allocated. Normally there are not so many such big objects, thus recording their allocation should not add any significant overhead.

In some rare cases you can record each created object e.g. when allocation information for some particular object must be obtained. To achieve this, set "Record each" to 1.

You can control recording of allocations from UI, or via Profiler API. You can also record allocations from the start of application execution (see Running applications with Profiler).

You can start and stop recording of allocations during execution of your application as many times as you wish. When allocations are not recorded, memory profiling adds no performance overhead to the application being profiled.

Recorded allocations are shown in Allocations view, Garbage collection view and Quick info

 

7.4 Shallow and retained sizes

YourKit Java Profiler is capable of measuring shallow and retained sizes of objects.

Shallow size of an object is the amount of memory allocated to store the object itself, not taking into account the referenced objects. Shallow size of a regular (non-array) object depends on the number and types of its fields. Shallow size of an array depends on the array length and the type of its elements (objects, primitive types). Shallow size of a set of objects represents the sum of shallow sizes of all objects in the set.

Retained size of an object is its shallow size plus the shallow sizes of the objects that are accessible, directly or indirectly, only from this object. In other words, the retained size represents the amount of memory that will be freed by the garbage collector when this object is collected.

To better understand the notion of the retained size, let us look at the following examples:

In order to measure the retained sizes, all objects in memory are treated as nodes of a graph where its edges represent references from objects to objects. There are also special nodes - GC root objects, which will not be collected by Garbage Collector at the time of measuring (read more about GC roots).

The pictures below show the same set of objects, but with varying internal references.

Figure 1:
Figure 2:

Let us consider obj1.
As you can see, in both pictures we have highlighted all of the objects that are directly or indirectly accessed only by obj1. If you look at Figure 1, you will see that obj3 is not highlighted, because it is also referenced by a GC root object. On Figure 2, however, it is already included into the retained set, unlike obj5, which is still referenced by GC root.

Thus, the retained size of obj1 will represent the following respective values:

  • For Figure 1: the sum of shallow sizes of obj1, obj2 and obj4
  • For Figure 2: the sum of shallow sizes of obj1, obj2, obj3 and obj4

Looking at obj2, however, we see that its retained size in the above cases will be:

  • For Figure 1: the sum of shallow sizes of obj2 and obj4
  • For Figure 2: the sum of shallow sizes of obj2, obj3 and obj4

In general, retained size is an integral measure, which helps to understand the structure (clustering) of memory and the dependencies between object subgraphs, as well as find potential roots of those subgraphs.

 

7.5 Memory views

 

7.5.1 Objects view

Purpose

Allows comprehensively examine a set of objects.

How can be opened

  • Tab "All Objects" opens automatically on memory snapshot opening and represents all live objects.
  • Memory | Selected Objects (F4) works in any memory view if selection represents live objects.
  • Memory | Instances by Class... (Ctrl+N) opens all instances of a class by its name.
  • Memory | Strings by Pattern... (Ctrl+F) opens instances of strings, char arrays or byte arrays that match given text pattern.
  • Memory | Predefined Set... opens objects that belong to one of sets specified in Settings | Sets of Objects....

The sections provide different 'views' of the set:

Class List - examine how memory is distributed among instances of different classes

Class loaders - distribute objects by class loader

Biggest Objects - find individual objects that retain most of memory

Merged Paths - examine how objects are retained

Generations - distribute objects by time of their creation

Object Explorer - browse individual objects

Allocations - explore methods where objects were created (available only if snapshot contains recorded object allocations).

 

7.5.1.1 Class list

This view is a powerful tool for examining how memory is distributed among instances of different classes.

Information for a class is shown in four columns: "Name", "Objects" (number of objects), "Shallow Size" and "Retained Size" (for details please see Shallow and retained sizes).

Classes whose objects retain most memory are shown at the top, as the list is sorted by retained size.

On opening the view, estimated retained sizes are shown instead of exact sizes, which cannot be immediately calculated. The exact sizes may be obtained by using "Calculate exact retained sizes" balloon above the "Retained Size" column. However, for most classes the estimation is very close to the exact value, so there is almost no need to run exact size calculation.

You can narrow down the list by typing a class name in the text field.

Please also consider Memory | Instances by Class... (Ctrl+N), which opens all instances of a class by its name.

 

7.5.1.2 Biggest objects (dominators)

This view shows individual objects that retain most of memory. The objects are shown as a dominator tree. That is, if object A retains object B, then object B will be nested in object A's node. Read more about retention.

This information can be useful to explore and reduce memory usage. In particular, it helps finding memory leaks caused by individual objects. Sometimes you can learn a lot by looking at memory distribution in terms of individual objects.

Also consider "Class list" which shows similar information for objects grouped by classes.

 

7.5.1.3 Object generations

Generations distribute objects by time of their creation, and are thus very helpful in finding memory leaks and performing other analysis of how heap content evolves over time.

When an object is created, it is associated with the current generation number. The generations are sequentially numbered starting from 1. The current generation number is automatically advanced on capturing memory snapshot. It can also be explicitly advanced with the help of "Advance Object Generation Number" toolbar button, as well as via API.

The generation represents an object's age: the smaller the generation number, the older the object.

All tabs representing live objects have a "Generations" view. In this view, you can see objects separated by time of their creation:

To show generation for a single object, use Quick Info:

See also the typical memory leak detection scenario.

 

7.5.1.4 Class loaders

"Class loaders" view shows objects grouped by class loader

For each loader, the number of loaded classes is shown, as well as the number of classes without instances; this information can help in finding leaked loaders.

Paths from GC roots to the loader object are explicitly available as a slave view "Paths to Loader". This allows to learn why particular loader is retained in memory

 

7.5.1.5 Merged paths

'Merged paths' view is a tool for examining how objects are retained. It is especially useful for analyzing objects of classes with a great number of instances, such as int[], java.lang.String etc.

'Merged paths' is similar to 'Paths from GC roots' view; however, it shows not paths through individual objects, but paths from multiple objects grouped by class.

For example, see the picture below. The 'Merged paths' view shows that the memory held by int[] instances is mostly retained by IntegerInterleavedRaster instances, which are in turn retained by BufferedImage and OffScreenImage.

Another difference between 'Merged paths' and 'Paths from GC roots' is that 'Merged paths' is build on dominator tree while 'Paths from GC roots' is build on full object reference graph. This means that some intermediate nodes seen in 'Paths from GC roots' may be missing in 'Merged paths' for objects which are retained indirectly.

 

7.5.1.6 Object explorer

Outgoing references

Shows all objects of the set and allows you to browse their outgoing references. Outgoing references of an object are fields or array elements of that object that point to other objects.


Incoming references

Shows all objects of the set and allows you to browse their incoming references. Incoming references of an object are references to that object.

DO NOT use "Incoming references" to find out why an object is retained in memory. Use paths instead.

 

7.5.1.7 Allocations

This section is available only for snapshots that contain any recorded object allocations.

Allocations let you discover methods where objects were created.

  • Call tree

    Shows a top-down call tree with the methods in which objects from the set were created, either for each particular thread ("by thread")

    or with calls from all threads merged ("all threads together").

    The tree is shown according to current filters.

  • Hot spots

    Shows methods where the greatest number of objects from the set ("Hot spots by object count")

    or objects with the greatest total shallow size ("Hot spots by object size") were created.

    Methods are shown according to current filters:

    • non-filtered methods (typically, methods from the source code of profiled application)
    • filtered methods (typically, methods from core classes and used libraries) that were directly called from non-filtered methods or are at the top of thread stack trace (Thread.run()).

  • Method list

    Methods are shown according to current filters:

    • non-filtered methods (typically, methods from the source code of profiled application)
    • filtered methods (typically, methods from core classes and used libraries) that were directly called from non-filtered methods or are at the top of thread stack trace (Thread.run()).

    For each method, the list shows the number and shallow size of objects it had created.

    You can narrow down the list by typing a method's name in the text field.

 

7.5.2 Dead objects view

"Dead objects" view (Memory | Dead Objects) shows objects that are not accessible from GC roots but still present in the snapshot (i.e. not collected yet). The view can be used to analyze excessive garbage allocation, especially if the snapshot does not contain recorded object allocation information.

Class list, generations, class loaders and object explorer are available for dead objects.

 

7.5.3 Method merged callees view

This view is available only for snapshots that contain any recorded object allocations.

This view shows merged callees for a particular method that allocated objects. In other words, it shows all call traces started from that method. This gives a summary of method execution, and its "overall" behavior.

To open this view for the selected method, use Memory | Method Merged Callees (Ctrl+M).

See also:

 

7.5.4 Method back traces view

This view is available only for snapshots that contain any recorded object allocations.

This view shows where a particular method, that allocated objects, was called.

To open this view for the selected method, use Memory | Method Back Traces (Ctrl+Shift+M).

See also:

 

7.5.5 Quick info view

"Quick Info" view shows useful information about selected object(s) and is available:

  • as a slave view
  • as a popup window invoked with Memory | Quick Info (Ctrl+Q) action.

The view shows retained and shallow size and object count for the current selection:

If a single object is selected, its generation is shown. If allocation trace is available, it is shown as well.

For a byte array "Quick info" shows its text representation in specified encoding (the snapshot must contain primitive values):

If object is a GC root of type "Stack Local" or "JNI Local", corresponding stack trace is shown, as well as local variable name if available:

 

7.5.6 GC roots view

The so-called GC (Garbage Collector) roots are special objects for garbage collector. The objects it collects are those that 1) are not GC roots and a) are not accessible by references from GC roots.

"GC Roots" view shows garbage collector roots sorted by types.

"GC Roots" view is NOT the best place to start memory leak detection - see Working with paths for a better approach.
Instead, "GC Roots" view acts as an overview of all objects that could not be collected at the moment the snapshot was created. The view is provided for information purposes only.

For memory leak analysis please use the Find paths feature.

 

7.5.7 Leak detection: working with paths

YourKit Java Profiler provides a unique and very powerful way to detect memory leak - calculation of paths between objects in memory.
A path is a very simple and intuitive concept. A path between Object 1 and Object n is a sequence of objects where:

  • First element is Object 1
  • Each element in the sequence, starting with the second one, is referenced from its predecessor
  • Last element is Object n

There are two actions in YourKit Java Profiler for finding paths:

  • Select an object and use Memory | Paths from GC Roots... (Ctrl+P) to find out why that object is retained in memory. This action is needed when you have found a leaked object and want to fix the memory leak.
  • Memory | Paths between Predefined Sets... is the most common way to find out how an object of the source set references objects of the target set.

You can limit the number of paths to find. It is guaranteed that the shortest paths are found first, i.e. there are no paths shorter than the ones displayed.

 

7.6 Inspections

Typical memory-related problems can be recognized with the help of the "Inspections" feature. Inspections enable automatic high-level analysis of application memory. Each inspection automatically detects a specific memory issue. Performing this type of analysis by hand would be a very complicated (if at all possible) task.

With the help of inspections you can easily find the causes and possible solutions of usual memory-related problems.

The "Inspections" view is added to any tab representing objects, such as "All Objects" or any subset of objects. Inspections for all objects (i.e. for the entire snapshot) are also available via top-level tab "Inspections'.

(1) To run all inspections as a batch use "Run All Inspections" button.
(2) To run a single inspection, select it in the tree and use "Run This Inspection Only" button (this is especially useful if you want to apply the changes made to an inspection's options).

All inspections are grouped by category:

Duplicate Strings

Find all java.lang.String's with identical text values. Problem: Duplicate strings waste memory.
Possible solution: Share string instance via pooling or using intern().

Null Fields

Find instance fields with high percentage of 'null' values.
Problem: Possible memory waste.
Possible solutions: If some of the fields are not used, get rid of them rarely assigned fields can be moved to subclasses in the class hierarchy.

Sparse Arrays

Finds arrays with big number of 'null' elements.
Problem: Possible memory waste.
Possible solution: Use alternate data structures e.g. maps or rework algorithms.

Zero Length Arrays

Find multiple instances of zero-length arrays of particular type.
Problem: Memory waste and additional load for garbage collector.
Possible solution: Use empty array per-class singleton e.g. via a static field in class.

Objects Retained by Inner Class Back References

Find objects retained via synthetic back reference of its inner classes.
Problem: Such objects are potential memory leaks.

Lost SWT Controls

Find SWT control instances not accessible from shown UI.
Technically, it finds instances of org.eclipse.swt.widgets.Control which are not accessible from org.eclipse.swt.widgets.Display's field 'controlTable'
Problem: Possible memory leaks.
Possible solutions: Examine paths to lost objects to see if they really leaked

Highly Referenced Objects

Finds objects referenced by a large number of other objects.
Possible problems: Incorrect relations between objects in memory, logical errors and/or non-optimal data structures.

Self Referencing Objects

Finds objects with fields referencing 'this'.
Problem: Possibly incorrect logic and/or memory waste.
Possible solution: Remove redundant fields.

Non-Serializable Objects Referenced from Serializable Objects

If a class implements interface java.io.Serializable and one of its serialized fields refers to a non-serializable object (directly or through intermediate objects), java.io.NotSerializableException will be thrown in runtime on attempt to serialize an instance of this class. This inspection automatically detects such situations.

Which objects are inspected

You can inspect all objects implementing Serializable, selecting "Inspections" on the "Memory" tab, or only particular serializable objects.

For example, test whether HTTPSessions would have serialization problems (assume memory snapshot is open):

  • Open all instances of HTTPSession in a new tab: "Memory | Instances by Class... (Ctrl+N)", type "HTTPSession" and press Enter; "Include instances of subclasses" should be selected
  • Click "Inspections" link in the tab
  • Select "Non-Serializable Objects Referenced from Serializables" in the list and run it

Which fields are serialized

  • Class can explicitly specify the list of its serializable fields with the help of static field serialPersistentFields
  • Otherwise, instance fields without transient modifier are serializable

If a serializable class overrides writeObject(ObjectOutputStream) and readObject(ObjectInputStream) methods to change the default serialization behavior, it is impossible to automatically find out what fields will actually be serialized. Thus, the inspection can provide incorrect results for such classes. However, this should not be a big problem, because in most cases this only leads to "false alarms": the inspection would report a referenced non-serializable object which is not actually serialized by writeObject(ObjectOutputStream).

Please learn more about serialization in this article: http://java.sun.com/developer/technicalArticles/ALT/serialization/

Limitation

This inspection is only available for the profiler's own format snapshots, and is not available for HPROF-format snapshots.

The problem with HPROF snapshots is that they do not contain essential information needed for this inspection:

  • It is unknown which classes are serializable, as there is no information about interfaces implemented by particular class
  • It is unknown which fields are transient

The profiler cannot obtain missing data as the HPROF snapshots are produced by a JVM internal dumper which stores only fixed kinds of information.

 

7.7 Comparing memory snapshots

This feature lets you compare any two memory snapshots.

To locate memory leaks, consider using the object generations feature.

To compare snapshots:

  • Open both snapshots.
  • Select one of them.
  • Use File | Compare Snapshot with... (also available from the popup menu) and select the snapshot to compare with.

A tab with "Comparison" view will open. The "Comparison" view contains the memory views "Class tree" and "Class list" with 2 columns: Objects (+/-) and Size (+/-). These display the differences in object counts and sizes. Positive values mean that Snapshot 2 (the later memory state) has more objects and/or its objects have the bigger total size.


100% of size corresponds to the total size of all objects in the old snapshot. Likewise, 100% of count corresponds to the object count in the old snapshot.

 

7.8 Automatically trigger snapshot capture on event

Three kinds of triggers are available:

When you are connected to the profiled application, the current triggers status is shown in control panel:

To toggle triggers click the button selected on the picture above.

 

7.9 Automatically capture snapshot on low memory

You can instruct the profiler to automatically capture memory snapshot when used memory reaches the specified threshold.

When used memory constantly increases, this often means there's a memory leak. Based on this concept, this feature greatly simplifies the detection of such situations in e.g. long-running applications such as servers. One of the benefits is that, after being triggered, the feature requires no further human interaction.

Please also consider the built-in ability of modern Sun Java virtual machines to dump memory on OutOfMemory. The JVM's internal light-weight dumping algorithm is used. This algorithm is specially designed to work in low memory conditions, when the JVM general purpose profiling interface JVMTI used by profilers may fail due to low resources.

To toggle this feature, connect to the profiled application and press the button shown on the picture below:

Then, if the threshold is reached, a memory snapshot will be created, a notification will be shown in the UI and the feature will deactivate. You can enable it again afterwards.

By default, when the profiled application starts, this feature is disabled. You can change this

 

7.10 Capture memory snapshots periodically

Please also consider the ability to capture memory snapshots on low memory or when OutOfMemory occurs.

You can instruct the profiler to capture a memory snapshot after a specified period of time.

When used memory constantly increases, this often means there is a memory leak. This feature greatly simplifies the detection of such situations in e.g. long-running applications such as servers. One of the benefits is that, after being triggered, the feature requires no further human interaction.

To toggle this feature, connect to the profiled application and press the button shown on the picture below:

Then, every time the specified period elapses, a memory snapshot will be created and the following notification will be shown in the UI:



How to capture snapshots periodically with the help of the profiler API

The following code snippet starts a thread that captures memory snapshots of the application itself each 10 minutes.

Please don't forget to add yjp-controller-api-redist.jar to the classpath. This jar can be found in <Profiler Installation Directory>/lib.

Read more about the profiler API.


import com.yourkit.api.Controller;

...

final Thread thread = new Thread(
  new Runnable(){
    public void run() {
      try {
        final Controller controller = new Controller();
        for (;;) {
          Thread.sleep(10 /* minutes */ * 60 /*seconds in minute*/ * 1000 /* millis in second */);
          controller.captureMemorySnapshot();
        }
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
);
thread.setDaemon(true); // let the application normally terminate
thread.start();

The second example is a small standalone Java application that each 10 minutes captures snapshots of a given profiled application. It can be used instead of the first snippet when direct code insertions into the profiled application are not possible or not desired.


import com.yourkit.api.Controller;

public class Dumper {
  public static void main(String[] args) {
    try {
      final Controller controller = new Controller(
        "localhost", // the host where profiled application runs
        10001 // the port the profiler agent listens on - CAN BE DIFFERENT IN YOUR CASE!
      );
      for (;;) {
        Thread.sleep(10 /* minutes */ * 60 /*seconds in minute*/ * 1000 /* millis in second */);
        controller.captureMemorySnapshot();
      }
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

7.11 Support of HPROF format snapshots

Java has a built-in feature for dumping heap snapshots to files in HPROF binary format. You can analyze these snapshots using all of the powerful features that YourKit Java Profiler provides for its own memory snapshots.

HPROF snapshots can be created in the following ways:

  • Automatically on OutOfMemoryError

    Read more...

  • Explicitly from within the profiler UI (Sun Java 6)
  • Explicitly via jmap utility (Sun Java 6)

    Sun Java 6 has the jmap utility that allows to connect to running Java process and dump Java heap:
    jmap -dump:format=b,file=file_name.hprof <pid>

    Hint: to learn the PID (process identifier) of running JVM, you can use jps or jconsole JDK utilities.

    The benefit is that memory can be analyzed on demand with no additional configuration of JVM or Java application. You can dump memory of any running instance of JVM that supports this feature.

  • Explicitly via jconsole utility (Sun Java 6)

    Sun Java has the jconsole utility that lets you to connect to a running Java 6 process for monitoring and management.

    Using jconsole, you can dump Java heap via HotSpotDiagnostic MBean

  • Produced with Java's built-in basic level profiling capability HPROF

    This approach has a lot of drawbacks and is not useful nowadays, but is mentioned here to show the complete picture.

How it works

HPROF snapshots (*.hprof) can be opened the same way as YourKit Java Profiler format snapshots (*.snapshot)

Known issues

Some HPROF snapshots do not contain values of primitive types. When such snapshots are opened in the profiler, values of java.lang.String's will not be available.

 

7.12 Values of primitive types

Values of primitive types (int, boolean, double etc.) are available in a memory snapshot if it is:

  • YourKit format snapshot (*.snapshot) of profiled application running on Java 6 or newer.

    Note: for Sun Java 6, update 4 or newer is required (because of a JVM bug 6540288)

  • HPROF-format snapshot of profiled application running on Java 6 or newer, or captured on OutOfMemoryError

Values of strings (i.e. instances of java.lang.String) are special case, and are available in YourKit format snapshots even if profiled application runs on Java 5. They help locating (identifying) a particular object among other objects of the same class. The profiler can search for strings, char arrays or byte arrays, even with regular expressions (Memory | Strings by Pattern... (Ctrl+F) action).

Values of primitive fields and arrays of primitive types are shown in object explorers:

Also, a text representation in specified encoding can be seen for byte[] in Quick Info.

 

7.13 Useful actions

Hint: Use popup menu and main menu to see what actions are enabled in particular context.

  • Memory | Quick Info (Ctrl+Q)

  • Memory | Instances by Class... (Ctrl+N) - shows instances of a class after you specify its name.
    Hint: You can also use this action to get quick info on the number of instances of a particular class: just type in the class name, and the instance count will appear next to the class name in the lookup list. Then hit ESC to close the lookup window, or press Enter to open the new tab.

  • Memory | Selected Objects (F4) - shows selected live objects in a new tab. Works in any memory view if the selection represents live objects.

  • Memory | Paths from GC Roots... (Ctrl+P) - finds paths from GC roots to the objects represented within the current selection. Works in any memory view if the selection represents live objects.

  • Memory | Strings by Pattern... (Ctrl+F) - shows instances of java.lang.String, char[] and byte[] matching the given text pattern. This can be useful to locate particular objects if their fields refer to a known string or a char sequence.

  • Tools | Open Declaration in IDE Editor (F7) - opens the currently selected class, field or method in the IDE editor. See IDE integration.

The following actions are available if a snapshot contains any recorded object allocations:
  • Memory | Method Merged Callees (Ctrl+M) - shows merged callees of the selected method.

  • Memory | Method Back Traces (Ctrl+Shift+M) - shows back traces of the selected method.

 

7.14 Set description language

This XML-based language provides the advanced ability to specify sets of objects in a declarative way. It can be used, for example, to examine memory distribution in automated memory tests.

To see some samples and define your custom sets, please use Settings | Sets of Objects... in the main menu. The sets can be opened via Memory | Predefined Set....

  • Tag objects specifies objects of a particular class, or multiple classes.

    Mandatory attribute class specifies the fully qualified class name. Wildcards (*) are also accepted.

    Optional attribute subclasses specifies whether subclasses should be accepted (subclasses="true"), or the class should match exactly (subclasses="false"). Default value is true.

    Examples:

    <objects class="com.company.MyClass"/> - all instances of the class com.company.MyClass and its subclasses

    <objects class="com.company.MyClass" subclasses="false"/> - all instances of com.company.MyClass but excluding instances of classes derived from com.company.MyClass.

    <objects class="*[]"/> - all arrays

  • Tag roots specifies all objects that are GC roots.

    Example:

    <roots/>

  • Tag and intersects the specified sets and returns all objects that are present in every set. There should be at least 2 nested sets.

    Example:

    The specification of all objects of classes that implement both com.company.MyInterfaceA and com.company.MyInterfaceB interfaces:

        <and>
          <objects class="com.company.MyInterfaceA"/>
          <objects class="com.company.MyInterfaceB"/>
        </and>
          
  • Tag or joins the specified sets and returns all objects that are present at least in one of the sets. There should be at least 2 nested sets.

    Example:

    The specification of all objects of the class com.company.A and its subclasses, and all objects of the class com.company.B and its subclasses:

        <or>
          <objects class="com.company.A"/>
          <objects class="com.company.B"/>
        </or>
          
  • Tag not specifies all objects that are not present in the specified set. There should be one and only one set specified.

    Example:

    The specification of all objects except for the objects of class com.company.A and its subclasses:

        <not>
          <objects class="com.company.A"/>
        </not>
          
  • Tag reachable-objects specifies objects accessible by references from the set specified via mandatory subtag from.

    The result will not include objects other than the ones specified via mandatory subtag object-filter. In terms of graphs, object-filter specifies allowed nodes.

    Mandatory subtag field-filter allows to search for objects reachable only from particular fields of classes. Restrictions for any number of classes can be specified as class subtags of field-filter:

        <field-filter>
          <class name="com.company.ClassA">
            <allowed field="field1"/>
            ...
            <forbidden field="field2"/>
            ...
          </class>
          <class name="com.company.ClassB">
            ...
          </class>
    
          ...
    
        </field-filter>
          

    For each class, you can specify any number of names (including none) of the allowed and forbidden fields. If at least one allowed tag is specified, only the allowed fields will be allowed for the class. If no allowed fields are specified, any fields except for the forbidden ones will be allowed for the class.

    Any fields of classes not specified in field-filter are acceptable.

    Example:

    The following example is a predefined set "Lost UI" (see Settings | Sets of Objects...). It lets you find all AWT/Swing UI controls that are not in the window hierarchy.

    UI controls are instances of java.awt.Component and its subclasses. Class java.awt.Container is a subclass of java.awt.Component and represents controls that contain other controls. To be shown, a control must be contained in windows, represented with objects of the class java.awt.Window with subclasses; java.awt.Window extends java.awt.Container.

    Our goal is to find any UI control (i.e. instance of java.awt.Component) not accessible from the window hierarchy. So we start from the windows (see the from section).

    We know that java.awt.Container stores its children in the field named component which is an array of components. According to this we form the object-filter and field-filter sections. Note that we have to include java.awt.Component[] to the object filter, so that the result of the entire reachable-objects tag includes arrays of components as well as components.

    To complete the task, we use a combination of and and not tags, to retrieve components that are not accessible from the windows in the specified way.

        <and>
          <objects class="java.awt.Component"/>
          <not>
    
            <reachable-objects>
              <from>
                <objects class="java.awt.Window"/>
              </from>
    
              <object-filter>
                <or>
                  <objects class="java.awt.Component"/>
                  <objects class="java.awt.Component[]"/>
                </or>
              </object-filter>
    
              <field-filter>
                <class name="java.awt.Container">
                  <allowed field="component"/>
                </class>
              </field-filter>
            </reachable-objects>
    
          </not>
        </and>
          
  • Tag retained-objects retrieves all objects that will be garbage-collected if all objects of the given set are garbage-collected. The given set is included. In other words, the retained set of set A is A itself plus all the objects accessible from A and only from A. These objects are called the retained set, and its size is called the retained size (see Shallow and retained sizes for more details).

    Example:

    The following specifies of all objects that will be garbage collected if all objects of the class com.company.A and its subclasses are garbage collected:

        <retained-objects>
          <objects class="com.company.A"/>
        </retained-objects>
          
 

7.15 Saving memory snapshot index

Opening a big memory snapshot sometimes takes a lot of time.

When a snapshot is loaded for the first time the profiler can store some pre-calculated information, the snapshot index, to a file alongside the original snapshot. The snapshot index will make the next snapshot opening much faster.

Please also consider other approaches to make snapshot opening faster.

The snapshot index files may be helpful in analyzing big snapshots on a 32-bit workstation. The index files can be generated on a 64-bit machine, via the profiler UI or programmatically (see below), and then transferred back to your workstation, in order to accelerate the memory snapshot opening in future.

Saving the index from the profiler UI

When you close a memory snapshot opened in the profiler UI or exit the profiler UI with memory snapshots open, the index files will be created automatically if they do not exist.

You can turn the automatic saving of index files off with the help of Settings | Save Snapshot Index on Close

Also, you can manually save current snapshot's index with the help of File | Save Snapshot Index. This can be useful if you have disabled the autosave.

Saving the index with the profiler API

You can create snapshot index file programmatically with the help of the profiler API:

      
File snapshotFile;
// ...
MemorySnapshot snapshot = new com.yourkit.api.MemorySnapshot(snapshotFile);
snapshot.saveIndexFile();
        
    

<Profiler Installation Directory>/lib/yjp.jar should be in the classpath.

Saving the index with command line tool

You can create snapshot index file using the following command:

java -jar <Profiler Installation Directory>/lib/yjp.jar -create-index <snapshot_file_path>

The index file location

When the profiler loads a memory snapshot, it looks for the index file in the same directory as the snapshot file. The index file name is formed from the snapshot file name with .index postfix added. If there is no index file found, the snapshot will be opened from scratch.

For example:
Snapshot named foo.snapshot will have index file name foo.snapshot.index
Snapshot named bar.hprof will have index file name bar.hprof.index

When saving snapshot index, make sure the directory where snapshot is located is writable and there is enough disk space (the index size can be comparable with the size of the snapshot.)

 

8 Garbage collection

Garbage collection telemetry

"Garbage Collection" telemetry will help you estimate garbage collector load. If garbage collection takes a significant amount of time, it is advised to profile memory allocation to pin-point and optimize the problematic code.

You can explicitly run garbage collection using "Force Garbage Collection" toolbar button:

Garbage collection in memory snapshot

If memory snapshot contains recorded allocations, "Garbage Collection" view, in addition to garbage collection telemetry described above, will also contain methods that were the sources of excessive garbage allocation.

See Solving performance problems for details on why one should avoid excessive garbage allocation.

The shown number and shallow sizes correspond to the objects that were created and recycled since the allocation recording was started and prior to the moment of the snapshot capture. (See also Memory snapshot, section "Inaccessible objects are treated as if they were already collected").

  • Call tree

    Shows a top-down call tree with methods in which collected objects were created, for each particular thread ("by thread")

    or with calls from all threads merged ("all threads together").

    The tree is shown according to current filters.

  • Hot spots

    Shows methods that made the biggest contribution to creating objects that were collected, either by number ("Hot spots by object count")

    or by shallow size ("Hot spots by object size").

    Methods are shown according to current filters:

    • non-filtered methods (typically, methods from the source code of profiled application)
    • filtered methods (typically, methods from core classes and used libraries) that were directly called from non-filtered methods or are at the top of thread stack trace (Thread.run()).

  • Method list

    Methods are shown according to current filters:

    • non-filtered methods (typically, methods from the source code of profiled application)
    • filtered methods (typically, methods from core classes and used libraries) that were directly called from non-filtered methods or are at the top of thread stack trace (Thread.run()).

    For each method, the list shows the number and shallow size of collected objects it had created.

    You can narrow down the list by typing a method's name in the text field.

 

9 Monitor profiling

Monitor profiling helps you analyze synchronization issues, including:

  • which threads were calling wait(), and for how long
  • which threads were blocked on attempt to acquire a monitor held by another thread (synchronized methods/blocks), and for how long

To start monitor profiling use "Start Monitor Profiling" toolbar button, after the profiler is connected to the profiled application.

Monitor profiling results are shown in the "Monitor Usage" view. Results can be grouped by waiting thread, by blocker thread or by monitor class name.

- waiting thread (thread which called wait())
- blocked thread (thread failed to immediately enter the synchronized method/block)
- blocker thread (thread that held the monitor preventing the blocked thread from entering the synchronized method/block)

(1) comboboxes to select results grouping
(2) checkbox to show blocked threads only (i.e. to filter out waiting threads)
(3) method back traces for the selection in the upper table

Percents in the tree are shown using the duration of monitor profiling (i.e. time passed since last start or clear) as 100%. This allows you to estimate the average percentage of time when thread waits/is blocked.

In some cases, it may also be useful to launch the application with monitor profiling started (see Additional options).

 

10 Exception telemetry

"Exceptions" telemetry shows exceptions which were thrown in the profiled application.

Exceptions may be grouped by their exception class or by thread in which they occurred. Selecting an exception in the upper table allows viewing the exception stack traces.

Checkbox "Show exceptions thrown and caught inside filtered methods" enables to filter out exceptions which have been thrown and caught in methods of library classes. By default, the checkbox is unselected, as such kind of exceptions are usually of no interest when profiling your application.

You can clear recorded exceptions with the help of corresponding toolbar button:

You can compare exception statistics of two snapshots with the help of "File | Compare Snapshot with...".

Disabling/enabling exception telemetry

Exception telemetry helps discovering performance issues and logic errors. In most cases, there is no significant overhead of collecting this information.

However, it makes sense to disable it in production J2EE servers in order to ensure minimum profiling overhead.

The telemetry is enabled by default, unless "disableexceptiontelemetry" startup option was specified.

When you are connected to the profiled application, use corresponding toolbar button to enable/disable the telemetry.

 

11 IDE integration

IDE integration provides:

  • ability to start profiled applications directly from an IDE
  • easy navigation from profiling results to profiled application source code

Please find details for each particular supported IDE:

 

11.1 Eclipse

Eclipse versions 3.3, 3.4, 3.5 and 3.6 are supported. Support for Eclipse 3.3 is provided only to allow a smoother migration to Eclipse 3.4 or newer. Future YourKit Java Profiler versions will support Eclipse 3.4 and newer only.

Plugin installation

To enable integration, you should install the profiler plugin.

To install the plugin, run the profiler.

When you run the profiler for the first time or after updating to a newer profiler version, you will be automatically prompted to install the plugin. Also, you can explicitly launch the plugin installation wizard via Tools | Integrate with IDE....


Eclipse 3.4 and newer: follow the instructions to complete plugin installation


Profiling from Eclipse

After the plugin is installed, Profile actions appear in the toolbar ...


... in the main menu ...


... and in context menus.


You can profile J2SE and J2EE applications and applets.

Additional launch parameters can be configured in the "Run | Profile...", "YourKit Java Profiler" tab.

The "Profile" action starts the profiled application, and connects to it in profiler UI (unless opposite behavior is configured). The output of the profiled application appears in console, same as for "Run" action.

Navigation action

When profiling applications, you usually need to browse the related source code to understand the performance problems at hands. After the problem is located, you edit the source code to fix it.

Instead of forcing you to tell profiler where the source code of your application is located and showing the code in feature-restricted custom-made "editor surrogate", YourKit provides an alternative approach. When you have a method, class or field selected in the profiler UI, just invoke Tools | Open Declaration in IDE Editor (F7), to automatically open the underlying source code in the editor of your IDE - the best place to browse and edit code.

The navigation action works on the current selection and is available in both CPU and memory views. Take note of the extremely useful ability to locate the code of anonymous classes and their methods, which is a very difficult thing to do manually.

 

11.2 Completing Eclipse 3.4 (or newer) plugin installation

Please follow instructions for your IDE:

Eclipse 3.4, JBuilder 2008 R2

Eclipse 3.5

Eclipse 3.6

MyEclipse 7.5-8.0

MyEclipse 8.5

 

11.2.1 Completing Eclipse 3.4 installation

(Optional) Uninstall YourKit Java Profiler 7.5 (or earlier) plugin, if it was installed

If you have YourKit Java Profiler 7.5 (or earlier) plugin installed, go to "Help | Software Updates... | Installed Software" in Eclipse's main menu, and uninstall the plugin.

Install the plugin

If you already have YourKit Java Profiler 8.0 plugin installed, just make sure it is up to date: go to "Help | Software Updates..." in Eclipse's main menu, select tab "Installed Software", then select YourKit Java Profiler plugin and invoke "Update...".

  • Go to "Help | Software Updates..." in Eclipse's main menu

  • Select tab "Available Software"

  • Press "Add Site..." button

  • Enter the following URL as the location:

    http://www.yourkit.com/download/yourkit80_eclipse34/

    Important: Eclipse update manager needs internet access. If your computer sits behind a proxy server, you will need to configure Eclipse accordingly: go to Window -> Preferences, then General -> Network Connections and enter the host name or IP and port of your proxy server.

  • YourKit update site will be shown on the list. Select YourKit Java Profiler plugin and press "Install...".

  • Restart Eclipse as suggested

Check that the plugin is successfully installed

After restarting Eclipse, you should see Profile action in the toolbar:

Read about using the plugin...

 

11.2.2 Completing Eclipse 3.5 plugin installation

(Optional) Uninstall YourKit Java Profiler 7.5 (or earlier) plugin, if it was installed

If you have YourKit Java Profiler 7.5 (or earlier) plugin installed, manually uninstall the plugin from within Eclipse.

Install the plugin

If you already have YourKit Java Profiler 8.0 plugin installed, just make sure it is up to date: go to "Help | Check for Updates" in Eclipse's main menu.

  • Go to "Help | Install New Software..." in Eclipse's main menu

  • Press "Add..." button

  • Enter the following URL as the location:

    http://www.yourkit.com/download/yourkit80_eclipse34/

    Important: Eclipse update manager needs internet access. If your computer sits behind a proxy server, you will need to configure Eclipse accordingly: go to Window -> Preferences, then General -> Network Connections and enter the host name or IP and port of your proxy server.

  • YourKit update site will be shown on the list. Select YourKit Java Profiler plugin and press "Next".

  • Restart Eclipse as suggested

Check that the plugin is successfully installed

After restarting Eclipse, you should see Profile action in the toolbar:

Read about using the plugin...

 

11.2.3 Completing Eclipse 3.6 plugin installation

(Optional) Uninstall YourKit Java Profiler 7.5 (or earlier) plugin, if it was installed

If you have YourKit Java Profiler 7.5 (or earlier) plugin installed, manually uninstall the plugin from within Eclipse.

Install the plugin

If you already have YourKit Java Profiler 8.0 plugin installed, just make sure it is up to date: go to "Help | Check for Updates" in Eclipse's main menu.

  • Go to "Help | Install New Software..." in Eclipse's main menu

  • Press "Add..." button

  • Enter the following URL as the location:

    http://www.yourkit.com/download/yourkit80_eclipse34/

    Important: Eclipse update manager needs internet access. If your computer sits behind a proxy server, you will need to configure Eclipse accordingly: go to Window -> Preferences, then General -> Network Connections and enter the host name or IP and port of your proxy server.

  • YourKit update site will be shown on the list. Select YourKit Java Profiler plugin and press "Next".

  • Press "OK"

  • Restart Eclipse as suggested

Check that the plugin is successfully installed

After restarting Eclipse, you should see Profile action in the toolbar:

Read about using the plugin...

 

11.2.4 Completing MyEclipse 7.5 plugin installation

Uninstall pre-8.0 plugin (if was installed)

If you have YourKit Java Profiler 7.5 (or earlier) plugin installed, go to "Help | Software Updates | Add/Remove Software..." in the main menu, and uninstall the plugin.

Install the plugin

If you already have YourKit Java Profiler 8.0 plugin installed, just make sure it is up to date: go to "Help | Software Updates | Check for Updates..." in the main menu.

  • Go to "Help | Software Updates | Add/Remove Software..." in the main menu

  • In "Add/Remove Software", press "Add"

  • Press "Add Site" button

  • Enter the following URL as the location:

    http://www.yourkit.com/download/yourkit80_eclipse34/

    Also specify arbitrary name for the update site, e.g. "YourKit"

    Important: Eclipse update manager needs internet access. If your computer sits behind a proxy server, you will need to configure Eclipse accordingly: go to Window -> Preferences, then General -> Network Connections and enter the host name or IP and port of your proxy server.

  • YourKit update site will be shown on the list. Select YourKit Java Profiler plugin and press "Next".

  • Restart MyEclipse as suggested

Check that the plugin is successfully installed

After restarting MyEclipse, you should see Profile action in the toolbar:

Read about using the plugin...

 

11.2.5 Completing MyEclipse 8.5 plugin installation

Install the plugin

If you already have YourKit Java Profiler 8.0 plugin installed, just make sure it is up to date: go to "Help | MyEclipse Configuration Center | Software..." in the main menu.

  • Go to "Help | MyEclipse Configuration Center " in the main menu

  • Switch to Software and press "Add Site" button

  • Enter the following URL as the location:

    http://www.yourkit.com/download/yourkit80_eclipse34/

    Also specify arbitrary name for the update site, e.g. "YourKit"

    Important: Eclipse update manager needs internet access. If your computer sits behind a proxy server, you will need to configure Eclipse accordingly: go to Window -> Preferences, then General -> Network Connections and enter the host name or IP and port of your proxy server.

  • In pop-up, press "Add to Profile..."

  • Then press "Apply 1 change..."

  • Accept the license and press "Next".

  • Restart MyEclipse as suggested

Check that the plugin is successfully installed

After restarting MyEclipse, you should see Profile action in the toolbar:

Read about using the plugin...

 

11.3 IntelliJ IDEA

IntelliJ IDEA versions 4.5, 5, 6, 7, 8, 9, 10 are supported.

Plugin installation

To enable integration, you should install the profiler plugin.

Note: If you had installed the plugin from an older YourKit Java Profiler version (4.0 or earlier), the plugin wizard may fail to uninstall the old plugin. This may cause a conflict of the two plugin versions on IDEA startup. To avoid this, it is recommended that you first manually remove the old plugin from IDEA (IDE Settings | Plugins) and only then install the new one.

To install the plugin, run the profiler.

When you run the profiler for the first time or after updating to a newer profiler version, you will be automatically prompted to install the plugin. Also, you can explicitly launch the plugin installation wizard via Tools | Integrate with IDE....

Profiling from IDEA

After the plugin is installed, the Profile actions are added to the main toolbar ...


... to the main menu ...


... and to context popup menus:


You can profile J2SE and J2EE applications and applets.

Additional launch parameters can be configured in the "Run/Debug Configurations" dialog, "Startup/Connection" tab of the selected configuration.

The "Profile" action starts the profiled application, and connects to it in profiler UI (unless opposite behavior is configured). The output of the profiled application appears in console, same as for "Run" action.

Navigation action

When profiling applications, you usually need to browse the related source code to understand the performance problems at hands. After the problem is located, you edit the source code to fix it.

Instead of forcing you to tell profiler where the source code of your application is located and showing the code in feature-restricted custom-made "editor surrogate", YourKit provides an alternative approach. When you have a method, class or field selected in the profiler UI, just invoke Tools | Open Declaration in IDE Editor (F7), to automatically open the underlying source code in the editor of your IDE - the best place to browse and edit code.

The navigation action works on the current selection and is available in both CPU and memory views. Take note of the extremely useful ability to locate the code of anonymous classes and their methods, which is a very difficult thing to do manually.

 

11.4 NetBeans

NetBeans versions 5.x, 6.x, 7.0 are supported.

Plugin installation

To enable integration, you should install the profiler plugin.

To install the plugin, run the profiler.

When you run the profiler for the first time or after updating to a newer profiler version, you will be automatically prompted to install the plugin. Also, you can explicitly launch the plugin installation wizard via Tools | Integrate with IDE....

Profiling from NetBeans

After the plugin is installed, Profile actions are added to the main toolbar ...

... and to context menu of the editor:

You can profile J2SE and J2EE applications and applets.

Additional launch parameters can be configured in the "Tools | Options", then "YourKit Profiler":

The "Profile" action starts the profiled application, and connects to it in profiler UI (unless opposite behavior is configured). The output of the profiled application appears in console, same as for "Run" action.

Navigation action

When profiling applications, you usually need to browse the related source code to understand the performance problems at hands. After the problem is located, you edit the source code to fix it.

Instead of forcing you to tell profiler where the source code of your application is located and showing the code in feature-restricted custom-made "editor surrogate", YourKit provides an alternative approach. When you have a method, class or field selected in the profiler UI, just invoke Tools | Open Declaration in IDE Editor (F7), to automatically open the underlying source code in the editor of your IDE - the best place to browse and edit code.

The navigation action works on the current selection and is available in both CPU and memory views. Take note of the extremely useful ability to locate the code of anonymous classes and their methods, which is a very difficult thing to do manually.

 

11.5 JBuilder 2008

Plugin installation

To enable integration, you should install the profiler plugin.

To install the plugin, run the profiler.

When you run the profiler for the first time or after updating to a newer profiler version, you will be automatically prompted to install the plugin. Also, you can explicitly launch the plugin installation wizard via Tools | Integrate with IDE....

Profiling from JBuilder 2008

After the plugin is installed, Profile actions appear in the toolbar ...


... in the main menu ...


... and in context menus.


You can profile J2SE and J2EE applications and applets.

Additional launch parameters can be configured in the "Run | Profile...", "YourKit Java Profiler" tab.

The "Profile" action starts the profiled application, and connects to it in profiler UI (unless opposite behavior is configured). The output of the profiled application appears in console, same as for "Run" action.

Navigation action

When profiling applications, you usually need to browse the related source code to understand the performance problems at hands. After the problem is located, you edit the source code to fix it.

Instead of forcing you to tell profiler where the source code of your application is located and showing the code in feature-restricted custom-made "editor surrogate", YourKit provides an alternative approach. When you have a method, class or field selected in the profiler UI, just invoke Tools | Open Declaration in IDE Editor (F7), to automatically open the underlying source code in the editor of your IDE - the best place to browse and edit code.

The navigation action works on the current selection and is available in both CPU and memory views. Take note of the extremely useful ability to locate the code of anonymous classes and their methods, which is a very difficult thing to do manually.

 

11.6 JBuilder 2008 R2

Please follow instructions for Eclipse 3.4

 

11.7 JDeveloper

JDeveloper 10g and 11g is supported.

Plugin installation

To enable integration, you should install the profiler plugin.

To install the plugin, run the profiler.

When you run the profiler for the first time or after updating to a newer profiler version, you will be automatically prompted to install the plugin. Also, you can explicitly launch the plugin installation wizard via Tools | Integrate with IDE....

Profiling from JDeveloper

After the plugin is installed, Profile actions are added to the main menu ...

... and to context menus:

In JDeveloper 10g Release 3 and newer, the action appears in the main toolbar as well:

You can profile J2SE and J2EE applications and applets.

Additional launch parameters can be configured in the "Project Properties" dialog, "YourKit Java Profiler" node.

The "Profile" action starts the profiled application, and connects to it in profiler UI (unless opposite behavior is configured). The output of the profiled application appears in console, same as for "Run" action.

Navigation action

When profiling applications, you usually need to browse the related source code to understand the performance problems at hands. After the problem is located, you edit the source code to fix it.

Instead of forcing you to tell profiler where the source code of your application is located and showing the code in feature-restricted custom-made "editor surrogate", YourKit provides an alternative approach. When you have a method, class or field selected in the profiler UI, just invoke Tools | Open Declaration in IDE Editor (F7), to automatically open the underlying source code in the editor of your IDE - the best place to browse and edit code.

The navigation action works on the current selection and is available in both CPU and memory views.

Note: navigation to inner classes is not possible because JDeveloper does not provide appropriate API.

 

12 Summary, snapshot annotation and automatic deobfuscation

The "Summary" tab provides an overview of JVM properties and parameters of profiled application, as well as a summary of application telemetry information.

The tab is available when the profiler is connected to profiled application, or when you open a saved snapshot.

Automatic deobfuscation

If the profiled application is obfuscated, YourKit Java Profiler can automatically restore original names of classes, fields and methods if you specify the path to the obfuscation log file (1). Deobfuscator can be configured for a specific snapshot, as well as when you are connected to the profiled application (in this case the deobfuscator will apply to live results and will be chosen by default for captured snapshots).

Snapshot annotation

The "Summary" view for a snapshot lets you store free-form text descriptions directly in the snapshot file (2).

 

13 Time measurement (CPU time, wall time)

This is an advanced topic. It provides additional details that you do not normally have to know to profile your applications.

There are two ways to measure time:

  • CPU time - the time actually spent by CPU executing method code
  • Wall time - the real-world time elapsed between method entry and method exit. If there are other threads/processes concurrently running on the system, they can affect the results.

CPU sampling/tracing

CPU sampling and tracing measure:

  • Wall time: For methods that rarely consume a lot of CPU directly; instead they perform network calls, involve OS background activity or delegate to other applications such as database engines. They include:
    • By default, basic file and socket I/O operations. See section 'Customization' below to learn how to change this.
    • J2EE queries
  • CPU time: for all other methods

Customization

To customize for which methods the wall time is measured, use "Settings | Wall Time Methods...":

The settings are applied each time you start CPU tracing or sampling. This means you can change the settings without restarting the profiled application.

Each line should be in this format:

<fully qualified class name> <method name> <method signature>

Wildcards ('*') are accepted. E.g. the following specifies all methods of class com.Foo.Bar, which names start with 'print':

com.Foo.Bar print* *

Default configuration is:

java.io.RandomAccessFile    readBytes    ([BII)I
java.io.RandomAccessFile    read         ()I
java.io.RandomAccessFile    write        (I)V
java.io.RandomAccessFile    writeBytes   ([BII)V
java.net.SocketInputStream  socketRead0  (Ljava/io/FileDescriptor;[BIII)I
java.net.SocketOutputStream socketWrite0 (Ljava/io/FileDescriptor;[BII)V


To measure CPU time for all methods, the settings should be empty.

Monitor profiling

Monitor profiling measures wall time for waiting and blocked threads.

 

14 Filters

Filters help you to reduce the depth of call trees. This can be done by skipping successive calls of methods from classes of standard libraries, application servers, etc., so you can more easily see the methods of the profiled application.

Filters are applied to views where method call stacks are shown, as well as to hot spot and method list views.

Filters are also used during profiled application runtime to reduce the profiling overhead.

Non-filtered methods are marked with a filled arrow . Filtered methods have an outlined arrow :


Select Settings | Edit Filters... in the main menu to configure filters.

While reviewing a snapshot, you can use different filters or use none at all. In other words, you do not need to start a new profiling session to start or stop using filters. Views are automatically updated when filter settings are changed.

 

15 User interface customization

Font type and size can be customized via Settings | User Interface....

Note: This action is not available on Windows and Mac OS X. Manual configuration is not needed for these systems, because system settings can be obtained automatically.

 

16 Export of profiling results to HTML, CSV, plain text

You can export all reports and data to:

  • HTML, optionally packing all generated files to a single ZIP archive
  • CSV ("comma separated values") format
  • Plain text format

In particular, you can export telemetry data (right-click a graph to invoke a popup menu):

"File | Copy To Clipboard..." (Ctrl+C or another platform specific shortcut) action copies text of selected row in all trees and lists.

 

17 Profiler API

The profiler API allows you to control profiling programmatically. Also, in your automatic memory tests you can open saved memory snapshots and examine them via the set description language.

To control profiling programmatically, also consider command line tool which in some cases may be a simpler approach.

Please find API JavaDoc here

Class com.yourkit.api.Controller allows you to profile (i.e. turn on and off profiling modes and capture snapshots) the application itself or another Java application. To use this part of the API, please include <Profiler Installation Directory>/lib/yjp-controller-api-redist.jar in the classpath.

Classes com.yourkit.api.MemorySnapshot and com.yourkit.api.Annotations support the analysis of captured memory snapshots and snapshot annotation. To use this part of the API, please include <Profiler Installation Directory>/lib/yjp.jar in the classpath. The code that uses the API should run on Java 5 or newer. Important: Do not remove yjp.jar from the installation directory. The API will not work with yjp.jar moved to an arbitrary directory, because it needs the other files from the installation.

 

18 Command line tool to control profiling

Command line tool is another way to control profiling, in addition to UI and API.

It has much in common with API and may also be used for automated profiling. You may prefer the command line tool to API in some cases as an easier solution not requiring any Java code to be written. However the command line tool provides less functionality than the API.

Also, the command line tool may be useful in remote profiling when you only have console access to the remote machine and no UI is available.

Run the tool with the following command:
java -jar <Profiler Installation Directory>/lib/yjp-controller-api-redist.jar <options>

To get list of available options, run:
java -jar <Profiler Installation Directory>/lib/yjp-controller-api-redist.jar

Also consider connecting to a remote application from locally running profiler UI, which may be a better approach.