Episode ini membahas penyempurnaan performa: profiling dengan JFR dan async-profiler, tuning heap dan JVM flags dengan GC G1 dan ZGC, optimasi startup time dan memory footprint, serta tuning cache dan connection pool.

Aplikasi yang lambat jarang butuh teknologi baru — biasanya butuh menemukan di mana waktu hilang. Episode 16 membahas performance dan JVM optimizations: cara mengukur, menemukan hambatan, lalu mengoptimalkan aplikasi Spring Boot dengan pengetahuan yang benar.
Kalian akan belajar memakai JFR dan async-profiler untuk profiling, mengatur JVM flags dan memilih garbage collector, mempercepat startup, serta mengecilkan memory footprint dan mengatur koneksi dengan tepat.
JFR adalah profiler bawaan JVM yang mencatat event runtime — alokasi memory, GC, thread, dan metode yang panas — dengan overhead sangat rendah. Rekam sesi saat aplikasi berjalan:
jcmd 1234 JFR.start name=profil duration=60s \
filename=profil.jfrjcmd 1234 JFR.start name=profil duration=60s filename=profil.jfr merekam profiling selama 60 detik ke file profil.jfr. Buka file tersebut di JDK Mission Control untuk menganalisis metode mana yang memakan waktu dan memory.
async-profiler mengukur CPU dan alloc secara sampling tanpa stopping threads. Satu command bisa menghasilkan flame graph:
./async-profiler -d 60 -o flamegraph -f flamegraph.html <pid>Perintah ./async-profiler -d 60 -o flamegraph -f flamegraph.html <pid> mengambil sampel selama 60 detik dan menghasilkan flame graph interaktif. Dari sini kalian langsung melihat jalur pemanggilan yang paling mahal.
Salah satu keputusan paling umum: berapa heap yang diberikan. JVM default menentukan heap sebagai persentase dari total memory, tapi untuk container sebaiknya diatur eksplisit:
java -Xms512m -Xmx1024m \
-XX:MaxMetaspaceSize=256m \
-jar target/belajar-spring-boot.jar-Xms menetapkan ukuran awal heap, -Xmx ukuran maksimal, dan -XX:MaxMetaspaceSize membatasi metaspace. Jangan memberi heap lebih besar dari memory container — JVM bisa kehabisan memory karena GC dan metaspace.
Java 21 mendukung dua garbage collector modern:
java -XX:+UseZGC -jar target/belajar-spring-boot.jarSebelum mengganti GC, ukur dulu profil aplikasi kalian. ZGC unggul untuk latency, G1 lebih efisien untuk throughput umum. Keputusan harus berdasarkan data profiling, bukan tren.
Spring Boot memulai banyak bean saat startup. Lazy initialization menunda pembuatan bean sampai pertama kali dipakai, mempercepat startup dengan mengorbankan sedikit latency request pertama:
spring:
main:
lazy-initialization: trueTeknik ini berguna untuk aplikasi yang butuh startup cepat — misalnya fungsi serverless atau auto-scaling — tapi pikirkan konsekuensinya: error konfigurasi baru muncul saat bean dipakai, bukan saat startup.
Beberapa langkah untuk memory footprint yang lebih kecil:
-Xmx sesuai kebutuhan nyata, bukan setinggi mungkin.Cache mengurangi beban database dengan menyimpan hasil pemanggilan yang sering berulang. Aktifkan @EnableCaching dan tandai method yang perlu di-cache:
@Service
public class ItemService {
@Cacheable("items")
public Item findById(Long id) {
return repository.findById(id)
.orElseThrow(() -> new ItemNotFoundException(id));
}
}Cache items menyimpan hasil findById sehingga panggilan berikutnya tidak menyentuh database. Tambahkan provider seperti Caffeine untuk cache in-memory yang cepat, dan gunakan @CacheEvict untuk mengosongkan cache saat data berubah.
HikariCP adalah connection pool default Spring Boot. Atur ukurannya sesuai kebutuhan — bukan sebanyak mungkin:
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
max-lifetime: 1800000maximum-pool-size menetapkan jumlah koneksi maksimal, connection-timeout waktu tunggu mendapatkan koneksi, dan max-lifetime umur maksimal koneksi. Ukuran pool yang terlalu besar justru membuang resource database.
Episode 16 membekali kalian dengan penyempurnaan performa: profiling dengan JFR dan async-profiler, tuning heap dan JVM flags dengan GC G1 atau ZGC, optimasi startup dan memory footprint, serta tuning cache dan connection pool.
Inti yang harus dibawa pulang:
-Xmx harus disesuaikan dengan memory container, jangan terlalu besar.@Cacheable mengurangi beban database.Di episode 17 selanjutnya kita akan membahas testing dan quality assurance — unit testing dengan JUnit 5 dan Mockito, integration testing dengan @SpringBootTest dan @WebMvcTest, contract testing dengan Spring Cloud Contract, serta Testcontainers untuk database dan dependency.