Profiling Java applications

This page describes how to modify your Java application to capture profiling data and have that data sent to your Google Cloud project. For general information about profiling, see Profiling concepts.

Profile types for Java:

  • CPU time
  • Heap (Alpha, requires Java 11 or App Engine standard environment)
  • Wall time (not available for Java 8 App Engine standard environment)

Supported Java language versions:

  • OpenJDK and Oracle JDK for Java 7, 8, 9, or 11.

Supported operating systems:

  • Linux versions whose standard C library is implemented with glibc.

Supported environments:

Enabling the Profiler API

Before you use the profiling agent, ensure that the underlying Profiler API is enabled. You can check the status of the API and enable it if necessary by using either the Cloud SDK gcloud command-line tool or the Cloud Console:

Cloud SDK

  1. If you have not already installed the Cloud SDK on your workstation, see Google Cloud SDK.

  2. Run the following command:

    gcloud services enable

For more information, see gcloud services.

Cloud Console

  1. Go to the APIs & Services dashboard:

    Go to APIs & services

  2. Select the project you will use to access the API.

  3. Click the Add APIs and Services button.

    Add APIs and Services

  4. Search for Profiler API.

  5. In the search results, select Stackdriver Profiler API.

  6. If API enabled is displayed, then the API is already enabled. If not, click the Enable button.

Installing the Profiler agent

Compute Engine

  1. Create an installation directory, for example, /opt/cprof, for the Profiler agent:

     sudo mkdir -p /opt/cprof

  2. Download the agent archive from the repository and extract it into the installation directory:

    wget -q -O- \
    | sudo tar xzv -C /opt/cprof


Modify the Dockerfile to create an installation directory for the Profiler agent, download the agent archive, and then extract the archive into the installation directory:

RUN mkdir -p /opt/cprof && \
  wget -q -O- \
  | tar xzv -C /opt/cprof

Istio on Google Kubernetes Engine:

If you are using Istio on Google Kubernetes Engine, then also do the following:
  1. Ensure you are using GKE 1.13.11-gke.11 or later.
  2. Grant the profiling agent access to the Google Cloud metadata server and to the Cloud Endpoints API by running the following command:
    kubectl apply -f agent_auth.yaml
    where the file agent_auth.yaml contains:
    kind: ServiceEntry
      name: whitelist-egress-googleapis
      - "" # Used to get token
      - "*"
      - number: 80
        protocol: HTTP
        name: http
      - number: 443
        protocol: HTTPS
        name: https
    kind: ServiceEntry
      name: whitelist-egress-google-metadata
      - # metadata server
      - number: 80
        name: http
        protocol: HTTP
      - number: 443
        name: https
        protocol: HTTPS
  3. To verify the configuration, run the following command:
    kubectl get serviceentry
    The following is an example of the response when the configuration was successful:
    NAMESPACE   NAME                               AGE
    default     whitelist-egress-google-metadata   20h
    default     whitelist-egress-googleapis        20h
  4. Configure the Istio pilot-agent to enable HTTP 1.0 in the outbound HTTP listeners:
    kubectl set env deployment/istio-pilot -n istio-system PILOT_HTTP10=1
  5. Nest the profiling agent's initialization in a retry loop that is configured to retry until Istio has completed its initialization and is handling network traffic. By default, the Java profiling agent performs a limited number of retries when accessing the Google Cloud metadata server. To specify the retry behavior of the profiling agent, use the following configuration options:


    For details on using these options, see Agent configuration.

Flexible Environment

When you use the Google Java 8 runtime base image or the Java 9 / Jetty 9 runtime base image, the Profiler agent is pre-installed, so there are no additional steps that you need to take to install the agent.

For all other base images, you need to install the agent. For example, the following Dockerfile contains the instructions to use the openjdk:11-slim image, to install the Profiler agent, and it defines the default parameters to be used when starting the application:

FROM openjdk:11-slim

COPY . .
RUN  apt-get update \
     && apt-get install wget \
     && rm -rf /var/lib/apt/lists/*

RUN mkdir -p /opt/cprof && \
    wget -q -O- \
    | tar xzv -C /opt/cprof

CMD ["java", "-agentpath:/opt/cprof/[OPTION1],[OPTION2]", "-jar", "PATH/TO/YOUR/JARFILE"]

To use this Dockerfile with App Engine flexible environment, you need to do the following:

  • Replace [OPTION1] and [OPTION2] with the agent configuration values needed for your application, and replace PATH/TO/YOUR/JARFILE with the path to your jar file.
  • Place the Dockerfile in the same directory as your app.yaml file.
  • Modify your app.yaml file to specify a custom runtime.

Standard Environment

When you use the Google Java 8 runtime environment or the Java 11 runtime environment, the Profiler agent is pre-installed, so there are no additional steps that you need to take to install the agent. For Java 11 Standard, it is pre-installed in /opt/cprof.

Outside Google Cloud

  1. Create an installation directory, for example, /opt/cprof, for the Profiler agent:

     sudo mkdir -p /opt/cprof

  2. Download the agent archive from the repository and extract it into the installation directory:

    wget -q -O- \
    | sudo tar xzv -C /opt/cprof

To list all versions of the agent available for downloading, run the following command:

gsutil ls gs://cloud-profiler/java/cloud-profiler-*

The command response is similar to the following:


To download a specific version of the agent, pass its URL to the download command. For example, to download the agent built on 28 October 2019, you would use the following statement:

wget -q -O- \
  | sudo tar xzv -C /opt/cprof

The version of the agent is logged during its initialization.

Loading the Profiler agent

To profile your application, start Java as you normally would to run your program, but specify the agent-configuration options. You specify the path to the agent library, and you can pass options to the library.

For the App Engine standard environment, the agent is automatically loaded and configured. Skip ahead to Starting your program, for details on configuring, and starting, your program.

Agent configuration

To configure the profiling agent, include the -agentpath flag when starting your application:


In this expression, [INSTALL_DIR] is the path to the profiling agent, while [OPTION1], [OPTION2], and [OPTION3] are agent configuration options. For example, if you replace [OPTION1] with -cprof_service=myapp in the previous expression, then you set the service name to myapp. There is no restriction on the number of options or their ordering. Supported configuration options are listed in the following table:

Agent option Description
-cprof_service If your application isn't running on App Engine, then you must use this configuration option to set the service name. For service name restrictions, see Service name and version arguments.
-cprof_service_version When you want the ability to analyze profiling data using the Profiler UI by the version of the service, use this option to set the version. For version restrictions, see Service name and version arguments.
-cprof_project_id When you are running outside of Google Cloud, use this option to specify your Google Cloud project ID. For more information, see Profiling applications running outside of Google Cloud.
-cprof_zone_name When your application is running on Google Cloud, the profiling agent determines the zone by communicating with the Compute Engine metadata service. If the profiling agent can't communicate with the metadata service, then you need to use this option.
Together, these two options define the retry policy that the profiler agent uses when it communicates with the Compute Engine metadata service. to gather your Google Cloud project ID and zone information.

Default policy is to retry up to 3 times waiting 1 second between attempts. This policy is sufficient for most configurations.
-cprof_cpu_use_per_thread_timers For the most accurate CPU time profiles, set this option to true. Use of this option results in increased per-thread overhead.

Default value is false.
-cprof_force_debug_non_safepoints By default, the profiling agent forces JVM to generate debugging information for all just in time (JIT) generated code, in addition to generating debug information for all safepoints. This results in the most accurate function and line-level location information for CPU time and heap profiles at the expense of additional agent overhead. You can disable the generation of debugging information for JIT code by setting this option to false.

Default value is true.
-cprof_wall_num_threads_cutoff By default, wall profiles aren't collected if the total number of threads in the application exceeds 4096. The limit ensures that during profile collection, the cost of traversing the stack of threads is minimal. If your service normally has more than 4096 threads and if you want to collect profiling data at the expense of additional overhead, use this flag to increase limit.

Default limit is 4096 threads.
-cprof_enable_heap_sampling To enable heap profiling for Java 11 and higher, set
-cprof_enable_heap_sampling to true. Heap profiling isn't supported for Java 10 and lower.

Heap profiling is disabled by default.

When you enable heap profiling, the sampling interval is set to 512 KiB by default. This interval is sufficient for most applications and incurs less than 0.5% overhead for the application. Sampling intervals from 256 KiB (262144) to 1024 KiB (1048576) are supported. For example, to set the sampling interval to 256 KiB, which doubles the sampling rate, add the agent option:
Similarly, to set the sampling interval to 1024 KiB, which halves the sampling rate, add the agent option:

Service name and version arguments

When you load the Profiler agent, you specify a service-name argument and an optional service-version argument to configure it.

The service name lets Profiler collect profiling data for all replicas of that service. The profiler service ensures a collection rate of one profile per minute, on average, for each service name across each combination service versions and zones.

For example, if you have a service with two versions running across replicas in three zones, the profiler will create an average of 6 profiles per minute for that service.

If you use different service names for your replicas, then your service will be profiled more often than necessary, with a correspondingly higher overhead.

When selecting a service name:

  • Choose a name that clearly represents the service in your application architecture. The choice of service name is less important if you only run a single service or application. It is more important if your application runs as a set of micro-services, for example.

  • Make sure to not use any process-specific values, like a process ID, in the service-name string.

  • The service-name string must match this regular expression:


A good guideline is to use a static string like imageproc-service as the service name.

The service version is optional. If you specify the service version, Profiler can aggregate profiling information from multiple instances and display it correctly. It can be used to mark different versions of your services as they get deployed. The Profiler UI lets you filter the data by service version; this way, you can compare the performance of older and newer versions of the code.

The value of the service-version argument is a free-form string, but values for this argument typically look like version numbers, for example, 1.0.0 or 2.1.2.

Starting your program

Compute Engine

Start Java as you normally would to run your program, and add the the agent-configuration options:

java \
    -agentpath:/opt/cprof/,-cprof_service_version=1.0.0 \


Modify the service container Dockerfile to start Java as you normally would to run your program, and add the agent-configuration options:

CMD ["java", \
    "-agentpath:/opt/cprof/,-cprof_service_version=1.0.0", \
    "-javaopt1=val1", "-javaopt2=val2", "-jar", "PATH/TO/YOUR/JARFILE", \
    "-programopt1=val1", "-programopt2=val2"]

Flexible Environment

Modify the app.yaml configuration file to set the PROFILER_ENABLE environment variable. Then start your program as usual:


See Defining environment variables for more information.

Standard Environment

Modify the entrypoint in app.yaml or the appengine-web.xml configuration file to include the GAE_PROFILER_MODE environment variable to instruct Profiler to collect CPU time and heap profiles, one time per minute on average, across all instances of the same deployment:

Java 11 runtime environment


runtime: java11
entrypoint: java -agentpath:/opt/cprof/ -jar myApp.jar
Java 8 runtime environment


    <env-var name="GAE_PROFILER_MODE" value="cpu,heap" />

Then start your program as usual.

See Defining environment variables for more information.

Agent logging

The profiling agent can report logging information for App Engine flexible environment, Compute Engine, and GKE. The profiling agent supports the following logging levels:

  • 0: Log all messages. Default logging level.
  • 1: Log warning, error, and fatal messages.
  • 2: Log error and fatal messages.
  • 3: Log only fatal messages and stop the application.

To enable writing logs to standard error with the default logging level, append -logtostderr to the -agentpath configuration.

To set the logging level to log only error and fatal messages, append -minloglevel=2 to the -agentpath configuration.

For example, to enable logging of error and fatal messages to standard error, append -logtostderr and ‑minloglevel=2 to the -agentpath configuration:

 java -agentpath:/opt/cprof/,-logtostderr,-minloglevel=2 -jar myApp.jar

What's next

To learn about the Profiler graph and controls, go to Using the Stackdriver Profiler Interface. For advanced information, go to the following: