Topik ini menjelaskan metrik memori dari mesin virtual Java (JVM) yang didukung oleh layanan sub-Pemantauan Aplikasi dari Application Real-Time Monitoring Service (ARMS).
Area memori proses Java
Gambar berikut menunjukkan area memori dari proses Java.
Karena kompleksitas mekanisme JVM, gambar hanya menampilkan area memori utama.
Cara ARMS mendapatkan detail memori JVM
Agen ARMS menggunakan MemoryMXBean yang disediakan oleh Java Development Kit (JDK) untuk mengumpulkan detail memori selama waktu proses JVM. Karena keterbatasan MemoryMXBean, kemampuan pemantauan memori JVM ARMS tidak mencakup semua area memori yang digunakan oleh proses Java. Untuk informasi lebih lanjut, lihat Antarmuka MemoryMXBean.
Memori heap
Heap Java adalah area memori inti di mana semua objek dialokasikan dan pengumpulan sampah (GC) dilakukan. Tergantung pada pengumpul sampah Java, ukuran maksimum heap memori yang didukung oleh ARMS mungkin sedikit lebih kecil daripada batas atas yang ditentukan pengguna untuk heap memori. Sebagai contoh, jika Anda mengatur parameter -XX:+UseParallelGC -Xms4096m -Xmx4096m, ukuran memori maksimum yang diizinkan (3,8 GB) sedikit lebih kecil daripada ukuran memori yang ditentukan pengguna (4 GB), seperti yang ditunjukkan pada gambar berikut. Hal ini karena MemoryMXBean tidak mencakup data dari area From Space dan To Space.
Secara umum, jika Garbage-First (G1) Garbage Collector digunakan, ukuran maksimum heap memori yang didukung oleh ARMS sesuai dengan parameter -Xmx atau -XX:MaxRAMPercentage yang ditentukan pengguna. Namun, jika ParallelGC, Concurrent Mark Sweep (CMS) Collector, atau Serial Garbage Collector digunakan, terdapat sedikit penyimpangan.
Metaspace
Metaspace digunakan untuk menyimpan metadata kelas, termasuk informasi struktur kelas, informasi metode, dan informasi bidang. Penggunaan metaspace umumnya stabil.
Memori non-heap
Memori non-heap yang didukung oleh ARMS mencakup area berikut: metaspace, ruang kelas terkompresi, dan cache kode. Karena keterbatasan MemoryMXBean, ARMS tidak mendukung semua area memori non-heap. Stack thread VM dan Java Native Interface (JNI) tidak didukung.
Metaspace: menyimpan metadata kelas. JDK 8 dan versi lebih baru mendukung penentuan ukuran default dan ukuran maksimum metaspace dengan mengonfigurasi
-XX:MetaspaceSize=Ndan-XX:MaxMetaspaceSize=N.Ruang kelas terkompresi: mengompresi dan menyimpan metadata kelas yang dimuat. Sebagai area memori JVM khusus, ruang kelas terkompresi mengurangi penggunaan memori aplikasi Java dengan membatasi ruang pointer. Ruang kelas terkompresi dapat ditentukan dengan parameter startup JVM
-XX:CompressedClassSpaceSize. Di JDK 11, ukuran default ruang kelas terkompresi adalah 1 GB.Cache kode: menyimpan kode asli yang dihasilkan oleh JVM. Berbagai sumber menghasilkan kode asli, termasuk loop interpreter, JNI, kompilasi just-in-time (JIT), dan metode Java. Kode asli yang dihasilkan oleh kompilasi JIT menempati sebagian besar ruang cache kode. Ukuran awal dan ukuran maksimum cache kode dapat ditentukan dengan parameter startup JVM
-XX:InitialCodeCacheSizedan-XX:ReservedCodeCacheSize.
Buffer langsung
Buffer langsung Java adalah buffer khusus yang mengalokasikan ruang langsung di memori sistem operasi, bukan di memori heap JVM. Buffer langsung dapat memberikan operasi I/O yang lebih cepat, mencegah overhead penyalinan memori, dan memproses data dalam jumlah besar secara efisien. Banyak operasi I/O meningkatkan penggunaan buffer langsung.
Analisis kebocoran memori heap
ARMS menyediakan kemampuan analisis komprehensif untuk kebocoran memori heap. Anda dapat menggunakan fitur pemantauan memori heap JVM untuk memeriksa apakah memori heap meningkat secara perlahan. Jika memori heap meningkat dalam waktu lama, Anda dapat menggunakan fitur snap tem memory atau profil kontinu yang disediakan oleh ARMS untuk menyelesaikan masalah kebocoran memori heap.
Analisis kebocoran memori non-heap
Jika memori heap relatif stabil sedangkan memori keseluruhan aplikasi terus meningkat, memori non-heap mungkin bocor. ARMS tidak menyediakan analisis memori non-heap. Anda dapat menggunakan alat Native Memory Tracking (NMT) untuk memantau permintaan memori non-heap. Untuk informasi lebih lanjut, lihat Dokumentasi Oracle.
NMT memerlukan latar belakang teknologi dan menimbulkan overhead kinerja sebesar 5% hingga 10% pada aplikasi. Kami menyarankan Anda mengevaluasi dampaknya pada aplikasi online sebelum menggunakan alat tersebut.
Pertanyaan Umum Memori
T: Mengapa jumlah memori heap dan non-heap yang ditampilkan di modul Pemantauan Aplikasi konsol ARMS sangat berbeda dari Resident Memory Size dalam KiB (RES) yang diperoleh dengan menjalankan perintah
top?J: Data yang dikumpulkan oleh Pemantauan Aplikasi berasal dari Java Management Extensions (JMX), tidak termasuk stack thread VM, stack thread lokal, dan memori non-JVM. Oleh karena itu, data memori JVM yang disediakan oleh Pemantauan Aplikasi berbeda dari RES yang diperoleh dengan menjalankan perintah
top.T: Mengapa jumlah memori heap dan non-heap yang ditampilkan di modul Pemantauan Aplikasi konsol ARMS sangat berbeda dari data memori yang disediakan oleh Managed Service for Prometheus dan Managed Service for Grafana?
J: Data yang dikumpulkan oleh Pemantauan Aplikasi berasal dari JMX, sedangkan data memori yang disediakan oleh Managed Service for Grafana berasal dari metrik kontainer yang diquery menggunakan Prometheus Query Language. Secara umum, nama metrik ini berisi container_memory_working_set_bytes. Faktanya, jumlah Resident Set Size (RSS) dan cache aktif dari grup kontrol memori dihitung.
T: Pod restart karena pembunuh kehabisan memori (OOM). Bagaimana cara menggunakan Pemantauan Aplikasi untuk menyelesaikan masalah ini?
J: Anda dapat menggunakan Pemantauan Aplikasi untuk menyelesaikan masalah perencanaan kapasitas memori heap dan buffer langsung dengan mudah. Namun, data memori yang diperoleh Pemantauan Aplikasi dari JMX tidak mencakup detail konsumsi RSS dari seluruh proses JVM. Oleh karena itu, Anda harus menggunakan ekosistem pemantauan Prometheus Kubernetes untuk menyelesaikan pembunuh OOM. Selain itu, perhatikan dua aspek berikut:
Apakah pod hanya memiliki model proses tunggal?
Anda perlu memeriksa apakah proses lain mengonsumsi memori.
Apakah ada kebocoran di luar proses JVM?
Sebagai contoh, glibc dapat menyebabkan kebocoran memori.