This episode covers JVM performance tuning: profiling with JVisualVM, JFR, and Flight Recorder, understanding the G1, ZGC, and Shenandoah garbage collectors, heap tuning and JVM flags, measuring latency versus throughput, and code optimization techniques.

Once the application runs, the next question is: how fast and efficient is it? Episode 16 covers performance tuning and garbage collection — how to profile the JVM, understand modern garbage collectors, configure the heap and JVM flags, and write optimal code.
JVM performance is strongly influenced by configuration and an understanding of garbage collection. This episode gives you the tools to find bottlenecks and the techniques to optimize them, from measurement to implementation.
JVisualVM is a graphical tool for profiling Java applications. For local applications, simply run:
jvisualvmJVisualVM shows CPU, memory, threads, and slow methods.
Java Flight Recorder (JFR) is a low-overhead profiler that is part of the JDK. Record while the application runs:
java -XX:StartFlightRecording=filename=aplikasi.jfr,duration=60s -jar aplikasi.jar-XX:StartFlightRecording records the profile for 60 seconds into a .jfr file, which can be analyzed with JMC (JDK Mission Control).
A garbage collector frees the memory of objects that are no longer referenced. A good GC keeps pauses short and throughput high. Choosing the right GC is an important decision.
G1 (Garbage First) has been the default since Java 9. G1 divides the heap into regions and targets a configurable pause time:
java -XX:MaxGCPauseMillis=200 -jar aplikasi.jar-XX:MaxGCPauseMillis=200 sets a maximum pause target of 200 milliseconds per GC cycle.
ZGC and Shenandoah are designed for very short pauses, even with terabyte heaps. Enable them with flags:
java -XX:+UseZGC -jar aplikasi.jarZGC suits latency-sensitive applications, while G1 is a balanced choice for most cases.
The heap size is controlled with -Xms (initial) and -Xmx (maximum). Make both the same to avoid resizing:
java -Xms512m -Xmx512m -jar aplikasi.jar-Xms512m -Xmx512m sets a fixed 512 MB heap, avoiding resizing overhead.
Some frequently used flags: -XX:+PrintGCDetails for GC logging, -XX:MetaspaceSize for class metadata, and -XX:+HeapDumpOnOutOfMemoryError to create a heap dump on OOM:
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/aplikasi.hprof -jar aplikasi.jarLatency is the time of a single operation; throughput is the number of operations per unit of time. The two often conflict. Good tuning balances both according to the application's needs.
Optimization starts with code, not just flags. Important principles: avoid excessive object allocation, use the right data structures, and avoid wasted work inside loops:
public class Optimasi {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("angka=").append(i).append(", ");
}
System.out.println(sb.length());
}
}StringBuilder.append is far more efficient than string concatenation with the + operator inside a loop, because it avoids creating repeated String objects.
Episode 16 covers performance tuning: profiling with JVisualVM, JFR, and Flight Recorder, understanding the G1, ZGC, and Shenandoah GCs, configuring the heap and JVM flags, measuring latency versus throughput, and code optimization techniques.
Key takeaways:
-Xms and -Xmx set the heap size.-XX:MaxGCPauseMillis targets the GC pause.In the next episode, episode 17, we will discuss testing and quality assurance — unit testing with JUnit 5, mocking with Mockito and the TDD approach, integration testing, contract testing, and test containers, plus static analysis with SpotBugs, Checkstyle, and PMD. Time to build a quality safety net!