Master Java Profiling: Tools, Techniques, and Real-World Tips

Transcript

Imagine that your code is a sleek sports car, but for some reason you're driving it with the handbrake on.

Today I will tell you how to release the handbrake and unleash the full potential of your application. Hi, my name is Catherine Edelveis, and in this video I will guide you through the intricacies of Java profiling. If you master profiling techniques, you will be able to find and fix the performance bottlenecks in your application quickly. We will look into key concepts and areas of Java profiling, try out some popular tools, and unveil the useful tips for Java profiling. Java profiling is the process of analyzing the application behavior running on Java Virtual Machine, and the analysis happens at runtime. Profiling usually deals with low-level processes and helps to get data on CPU usage, memory allocation, garbage collection, thread behavior, and other JVM operations. It also helps to identify memory leaks and thread locking issues.

Some modern profilers can also get data on the performance of database queries and web requests. Profiling is a must-have procedure for finding out the root causes of deteriorated performance of your Java programs. It may also be required if you are adding a critical feature to your application. There are two types of profilers: instrumenting and sampling ones. Instrumenting profilers insert method invocation logging into the application code. This approach is easier to implement, and developers don't even need to use specific tools for some basic measurements. But this approach offers very limited information and is associated with a serious overhead. Sampling profilers periodically receive from the JVM the stack trace of each thread running at this point of time, and then the profiler aggregates the samples and provides a general picture of application behavior. This approach has smaller overhead and can yield data on various JVM operations, but the results sometimes can be inaccurate depending on how often, for how long, and at which points the profiler took the samples.

Now let's look at some popular profiling tools. Jaba Flight Recorder or JFR is a profiling and diagnostic tool built into the OpenJDK. It collects data about various JVM events, and it can collect data on hundreds of event types, plus you can create your custom events. JFR recordings are binary log files that can be analyzed in JDK Mission Control. JDK Mission Control is a set of profiling and monitoring tools for Java applications. It has a graphic user interface, and you can use it as a standalone tool to monitor the application behavior in real-time or you can analyze JFR files in JDK Mission Control. You can start JFR upon application startup or use the jcmd tool to start and stop recordings at an arbitrary point of time. You can also perform continuous recording. You can analyze JFR files in JDK Mission Control. There are lots of reports for analyzing JVM events, and you can also customize them. So the advantages of JFR is that it is very easy to use because it is deeply integrated into the OpenJDK, and it can profile a very large number of events, and it has a very low overhead, so you can even use it in production. But it is not suitable for distributed systems. And it's a use only .jfr files.

VisualVM is an open-source Java profiler that uses the JMX API to collect the data. Basic VisualVM functionality include monitoring CPU and memory usage, garbage collection, thread behavior, and heap. You can use additional plugins to profile some other areas. To use VisualVM, simply choose a running local or remote JVM process and analyze the app in real time. You can also save the snapshots to analyze them later. To sum up, VisualVM is easy to use, it is free and open source, but it has limited functionality. Async Profiler is a free and open-source profiler that collects data on CPU cycles, hardware and software performance counters, allocations in Java Heap and contented lock attempts. It can produce JFR files and flame graphs. You can attach it as a ‘-javaagent’ at application startup, or connect to the running JVM process at an arbitrary point of time. You can analyze JFR files in JDK Mission Control and flame graphs in the browser. IAsync Profiler has a very low overhead, and it is free and open source, and it can also be embedded into other solutions. But there is no graphic user interface and it is not available for Windows. New Relic is not only a profiler, but an Application Performance Monitoring tool that offers a wide variety of features.

The features include: anomalies alert, infrastructure monitoring, security testing, and many more. The available services depend on the subscription plan, but there is a Freemium license for small teams and limited data ingest. Once you have completed the installation process, you can attach the New Relic agent to the JVM process just like any other profiler. The solution provides multiple dashboards to analyze the data in real-time or post factum. So, New Relic offers advanced analytics and it is suitable for distributed systems, but it takes time to set up, and a full set of features requires a subscription.

Digma integrates into Intellij IDEA as a plugin. It uses OpenTtelemetry under the hood to collect the data about the running code, and then provides reports on performance bottlenecks, code smells, and other performance issues related to your code. It can collect data on CPU and heap usage too, but its main focus is on the code. Using Digma is super easy. Simply install the plugin, follow the instructions to set up the analytics engine, and you're ready to go. So each time you run your code with Digma enabled, it runs silently in the background and collects data about your code. And then you can analyze the reports right in the Intellij IDEA. So Digma is really simple to use and it offers unique insights into the code. But it has limited analytics of low-level JVM processes, and it is available only as an Intellij IDEA plugin. JProfiler is a Java profiler with the graphic user interface. It offers a wide range of features, including CPU and memory profiling, database queries profiling, and web request profiling. It also uses an advanced tool called heap walker to identify the memory leaks. You can use it separately or integrate with your IDE as a plugin. It also offers a facilitated access to Kubernetes and Docker environments. It is possible to monitor the app in real time, or save the snapshots and analyze them later. So JProfiler can profile various areas and it has a convenient user interface, but it is a commercial product. YourKit is a Java profiler that can retrieve the data about multiple areas: CPU and memory, threads, database queries, web requests. It comes with a user interface, but it can also be used as a command line tool. The profiling results can be exported into various formats, including the flame graphs. Another useful feature called ‘What-If’ can analyze the possible improvements of a supposed performance optimizations without reprofiling the code. So YourKit offers deep analytics and some unique features, but it is a commercial product. All right, let us now look at the best practices of Java profiling. It is very tempting to grab a feature-packed profiler, collect tons of data about your code, and dig into optimizations. Well, don't do that. Premature optimization is the root of all evil. If SLAs are not broken and cloud costs don't spill over the edge, don't waste your time on fine-tuning small imperfections.

Check against the established key performance indicators and solve the problems that prevent your team from reaching them. Speaking of KPIs, choose the areas that are most important to optimize. Also, select the metrics that are most important for each area. Use this data as a reference when studying the profiling data. The profiling data is not always accurate. It depends on numerous factors: when the samples were taken, for how long, the profiler overhead, and the frequency of sampling, to name a few. So you can choose a low-overhead profiler and adjust the period of sampling. Or you can also use different profilers and then compare the results. Profiling an application on the local machine will not always give relevant results. Profile the application in Docker, Kubernetes, or in any other environment where your application runs. The application may behave differently in different environments. Also, use load testing and stress testing to see what happens in critical situations. Profilers can give information about low-level processes in the JVM, such as CPU and memory usage, but it is only part of the deal. You should use additional tools to get a data on response times, transaction rates, Inter-service communication, uptime, and so on.

Consider using an application performance monitoring tools such as New Relic to get the full picture of your application behavior. Today we looked at different tools and techniques for Java profiling. If you choose the right profiling tool that best suits your need and follow the best practices of profiling, you will be able to get valuable data about the behavior of your application and solve the performance issues quickly. If this video was useful to you, like it and subscribe to our channel. See you next time!

Summary

If your Java apps in the cloud struggle with high resource consumption, frequent container restarts, or slow response times, these five tips can help enhance their performance. First, set CPU and RAM limits properly based on load testing and account for Kubernetes overhead. Additionally, configure Kubernetes probes accurately, use a small base image to optimize container size, choose a suitable garbage collector, and reduce application startup and warmup time to ensure faster performance.

About Catherine

Java developer passionate about Spring Boot. Writer. Developer Advocate at BellSoft

Social Media

Videos
card image
Dec 9, 2024
How to use CRaC with Spring Boot in a Docker Container

CRaC (Coordinated Restore at Checkpoint) is an OpenJDK project designed to significantly reduce startup and warmup times of Java applications to milliseconds. This tutorial demonstrates using CRaC with a Spring Boot application running in a Docker container, specifically the Spring Boot Petclinic app (version 3.2 or later).

Videos
card image
Nov 29, 2024
OpenJDK Projects That We Anticipate

OpenJDK is actively evolving, with projects like Leyden, Valhalla, Babylon, and Lilliput aiming to enhance Java's performance and capabilities. Leyden focuses on faster startup and warmup by reusing precompiled code, while Valhalla introduces value objects, primitive classes, and specialized generics for better memory and runtime efficiency.

Further watching

Videos
card image
Jan 22, 2025
JEP 483: Ahead-of-Time Class Loading & Linking. Project Leyden in JDK 24

JEP 483 introduces Ahead-of-Time (AOT) Class Loading and Linking in JDK 24, which enhances Java application startup times by loading and linking classes ahead of time and storing them in a reusable AOT cache. This feature, part of Project Leyden, reduces the JVM's workload during startup without requiring changes to application code, though a training run mimicking production is needed to create an efficient cache. Early tests with a Spring Boot app showed significant improvements, cutting startup time from two seconds to just one second.

Videos
card image
Jan 14, 2025
How to use AppCDS with Spring Boot

This tutorial demonstrates how to use Application Class Data Sharing (AppCDS) and Ahead-of-Time (AOT) processing with Spring Boot applications to reduce startup time by 40–50%. AppCDS creates an archive of parsed classes for faster loading, requiring no code changes, and works both locally and in containers. The tutorial covers building optimized Docker images using Dockerfiles or Buildpacks for efficient deployment and improved performance.

Videos
card image
Dec 28, 2024
JDK 24: The New Features in Java 24

JDK 24 is in Rampdown Phase One, which means, we know all the JEPs targeted to this release. And there are a lot of them, so it is time to discuss this new Java release!