Belajar Quarkus - Native Image & Startup Optimization
Episode 16 of 24

Belajar Quarkus - Native Image & Startup Optimization

Episode ini membahas native image di Quarkus: kompilasi dengan GraalVM atau Mandrel, build time augmentation dan AOT compilation, optimasi startup time dan memory footprint, serta debugging native image dan tradeoff kompatibilitas.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

Di episode 1 kalian mendengar janji Quarkus: startup puluhan milidetik dan memory footprint kecil. Janji itu diwujudkan lewat native image — kompilasi ahead-of-time yang mengubah aplikasi Java menjadi executable mandiri tanpa JVM.

Episode 16 membahas native image secara menyeluruh: kompilasi dengan GraalVM atau Mandrel, build time augmentation dan AOT compilation, optimasi startup dan memory, serta debugging native image dan tradeoff kompatibilitas yang harus kalian pahami.

Quarkus Native Image dengan GraalVM atau Mandrel

GraalVM dan Mandrel

GraalVM adalah JDK dengan kompiler ahead-of-time. Mandrel adalah distribusi GraalVM yang dioptimalkan untuk Quarkus oleh Red Hat. Keduanya mampu mengkompilasi aplikasi menjadi native executable.

Membangun Native Image

Pastikan GraalVM terinstall, atau gunakan container build:

Build native image
./mvnw package -Pnative
./mvnw package -Pnative -Dquarkus.native.container-build=true

Flag -Dquarkus.native.container-build=true menjalankan kompilasi di dalam container, sehingga tidak perlu menginstall GraalVM lokal — cukup Docker berjalan.

Menjalankan Hasil Build

Setelah build, jalankan executable langsung:

Jalankan native executable
./target/belajar-quarkus-1.0.0-SNAPSHOT-runner

Tidak ada java -jar — file -runner adalah executable mandiri. Perintah curl http://localhost:8080/hello menunjukkan aplikasi merespons hampir seketika.

Build Time Augmentation dan AOT Compilation

Mengapa Bisa Begitu Cepat

Kunci kombinasi build-time augmentation (episode 2) dan AOT compilation. Quarkus mengolah metadata di fase build, lalu GraalVM mengkompilasi aplikasi dengan konteks statis: semua class yang dipakai sudah diketahui, reflection diizinkan secara eksplisit, dan kode yang tidak terpakai dibuang.

Pemrosesan di Build Time

Konfigurasi yang melibatkan nilai build-time (seperti quarkus.native.*) diproses saat kompilasi, bukan runtime. Ini sebabnya beberapa property tidak bisa diubah via environment variable — mereka sudah dibekukan di dalam executable.

Optimasi Startup Time, Memory Footprint, dan Size

Startup Time

Perbandingan tipikal:

Perbandingan startup
JVM mode       : 0.7-1.2 detik,   memory 150-300MB
Native image   : 0.02-0.08 detik, memory 50-80MB

Native image sangat cocok untuk serverless dan autoscaling Kubernetes di mana pod sering dibuat dan dihancurkan.

Mengurangi Ukuran Executable

Beberapa opsi konfigurasi:

Optimasi native build
quarkus.native.remove-unused-symbols=true
quarkus.native.enable-fallback-images=false
quarkus.native.strip-debug-symbols=true
quarkus.native.gc=epsilon
  • remove-unused-symbols: membuang simbol yang tidak terpakai.
  • gc=epsilon: garbage collector tanpa deallocation — cocok untuk workload pendek berlatensi minimal.

Profiling Startup

Ukur dan verifikasi optimasi:

Ukur waktu startup
time ./target/belajar-quarkus-1.0.0-SNAPSHOT-runner &
curl -s http://localhost:8080/q/health

time mengukur durasi eksekusi. Bandingkan JVM vs native untuk data konkret sebelum menurunkan target kinerja.

Debugging Native Image dan Tradeoff Kompatibilitas

Tradeoff yang Harus Dipahami

Native image bukan tanpa biaya:

  • Reflection perlu didaftarkan: pemakaian reflection dinamis harus dideklarasikan via @RegisterForReflection atau konfigurasi.
  • Proxy dinamis terbatas: JDK proxy perlu konfigurasi.
  • Waktu build lebih lama: kompilasi native bisa memakan beberapa menit.
  • Beberapa library tidak kompatibel: library yang sangat bergantung reflection dinamis bisa bermasalah.

Mendaftarkan Reflection

JavaDaftarkan class untuk reflection
import io.quarkus.runtime.annotations.RegisterForReflection;
 
@RegisterForReflection
public class DtoPesan {
    public String isi;
    public long timestamp;
}

@RegisterForReflection memberitahu GraalVM agar mempertahankan metadata reflection untuk DtoPesan di native image. Selalu audit kode yang memakai reflection sebelum build native.

Debugging Native

Mode JVM tetap tersedia untuk debugging; gunakan native di produksi. Untuk masalah khusus native, jalankan dengan laporan terperinci:

Logging native runtime
quarkus.native.enable-reports=true

quarkus.native.enable-reports=true menghasilkan laporan terperinci tentang fitur yang digunakan GraalVM — berguna saat terjadi error yang hanya muncul di native.

Penutup

Episode 16 memberi kalian senjata pamungkas Quarkus: memahami native image dengan GraalVM dan Mandrel, bagaimana build-time augmentation dan AOT bekerja sama, strategi optimasi startup, memory, dan ukuran, serta tradeoff dan cara debugging yang harus kalian ketahui sebelum deploy native di produksi.

Inti yang harus dibawa pulang:

  • Native image menghasilkan executable mandiri tanpa JVM.
  • -Dquarkus.native.container-build=true membangun native tanpa GraalVM lokal.
  • Startup native bisa 10-50 kali lebih cepat dari JVM mode.
  • Reflection dinamis harus didaftarkan dengan @RegisterForReflection.
  • Build native lebih lama; library berbasis reflection dinamis bisa bermasalah.
  • JVM mode tetap menjadi pilihan untuk development dan debugging.
  • quarkus.native.enable-reports=true membantu debugging khusus native.

Di episode 17 selanjutnya kita akan membahas testing dan quality assurance — unit testing dengan JUnit 5 dan Quarkus Test Framework, integration test dengan @QuarkusTest, mocking dan REST client testing, serta Testcontainers dan end-to-end testing.

Belajar Quarkus - Native Image & Startup Optimization | Belajar Quarkus