Skip to main content


Pyroscope uses async-profiler to collect profiling data from Java applications.

Supported platforms#



Java integration is distributed as a single jar file: pyroscope.jar. It contains native async-profiler libraries for:

  • Linux on x64;
  • Linux on ARM64;
  • MacOS on x64.
  • MacOS on ARM64.

Visit our GitHub releases page to download the latest version of pyroscope.jar.

The latest release is also available on Maven Central.

Profiling Java application#

You can start pyroscope either from your apps's java code or attach it as javaagent

Start pyroscope from app's java code#

Add pyroscope dependency:


Then add the following code to your application:

PyroscopeAgent.start(  new Config.Builder()    .setApplicationName("ride-sharing-app-java")    .setProfilingEvent(EventType.ITIMER)    .setFormat(Format.JFR)    .setServerAddress("http://pyroscope-server:4040")    // Optionally, if authentication is enabled, specify the API key.    // .setAuthToken(System.getenv("PYROSCOPE_AUTH_TOKEN"))    .build());

You can also optionally replace some pyroscope components

PyroscopeAgent.start(  new PyroscopeAgent.Options.Builder(config)    .setExporter(snapshot -> {      // Your custom export/upload logic may go here      // It is invoked every 10 seconds by default with snapshot of       // profiling data    })    .setLogger((l, msg, args) -> {      // Your custom logging may go here      // Pyroscope does not depend on any logging library      System.out.printf((msg) + "%n", args);    })    .setScheduler(profiler -> {      // Your custom profiling schedule logic may go here    })    .build());

Start pyroscope as javaagent#

To start profiling a Java application, run your application with pyroscope.jar javaagent:

export PYROSCOPE_SERVER_ADDRESS=http://pyroscope-server:4040
# Optionally, if authentication is enabled, specify the API key.# export PYROSCOPE_AUTH_TOKEN={YOUR_API_KEY}
java -javaagent:pyroscope.jar -jar app.jar


When you start pyroscope as javaagent or obtain configuration by pyroscope searches for configuration in multiple sources: system properties, environment variables, file. Properties keys has same name as environment variables, but lowercased and replaced _ with ., so PYROSCOPE_FORMAT becomes pyroscope.format

Java integration supports JFR format to be able to support multiple events (JFR is the only output format that supports multiple events in async-profiler). There are several environment variables that define how multiple event configuration works:

  • PYROSCOPE_FORMAT sets the profiler output format. The default is collapsed, but in order to support multiple formats it must be set to jfr.
  • PYROSCOPE_PROFILER_EVENT sets the profiler event. With JFR format enabled, this event refers to one of the possible CPU profiling events: itimer, cpu, wall. The default is itimer.
  • PYROSCOPE_PROFILER_ALLOC sets the allocation threshold to register the events, in bytes (equivalent to --alloc= in async-profiler). The default value is "" - empty string, which means that allocation profiling is disabled. Setting it to 0 will register all the events.
  • PYROSCOPE_PROFILER_LOCK sets the lock threshold to register the events, in nanoseconds (equivalent to --lock= in async-profiler). The default value is "" - empty string, which means that lock profiling is disabled. Setting it to 0 will register all the events.
  • PYROSCOPE_PUSH_QUEUE_CAPACITY sets the default pyroscope exporter push queue capacity. The default value is 32 snapshots.
  • PYROSCOPE_CONFIGURATION_FILE sets an additional properties configuration file. The default value is
  • PYROSCOPE_LABELS sets static labels in the form of comma separated key=value pairs. The default value is "" - enpty string, no labels.


It is possible to add dynamic tags (labels) to the profiling data. These tags can be used to filter the data in the UI.

Add labels dynamically: LabelsSet("controller", "slow_controller"), () -> {  slowCode();});

It is also possible to possible to add static tags (labels) to the profiling data:

Pyroscope.setStaticLabels(Map.of("region", System.getenv("REGION")));// or with Config.Builder if you start pyroscope with PyroscopeAgent.startPyroscopeAgent.start(new Config.Builder()    .setLabels(mapOf("region", System.getenv("REGION")))    // ...    .build());

Java profiling examples#

Check out the following resources to learn more about Java profiling:

Frame width represents CPU time per function