Saya mengalami masalah yang sama. Ini adalah masalah umum dengan glibc>=2.10
Obatnya adalah dengan menyetel variabel env ini
export MALLOC_ARENA_MAX=4
Artikel IBM tentang pengaturan MALLOC_ARENA_MAXhttps://www.ibm.com/developerworks/community/blogs/kevgrig/entry/linux_glibc_2_10_rhel_6_malloc_may_show_excessive_virtual_memory_usage?lang=en
Google untuk MALLOC_ARENA_MAX atau cari di SO untuk menemukan banyak referensi.
Anda mungkin ingin menyetel juga opsi malloc lainnya untuk mengoptimalkan fragmentasi rendah dari memori yang dialokasikan:
# tune glibc memory allocation, optimize for low fragmentation
# limit the number of arenas
export MALLOC_ARENA_MAX=2
# disable dynamic mmap threshold, see M_MMAP_THRESHOLD in "man mallopt"
export MALLOC_MMAP_THRESHOLD_=131072
export MALLOC_TRIM_THRESHOLD_=131072
export MALLOC_TOP_PAD_=131072
export MALLOC_MMAP_MAX_=65536
Mungkin juga ada kebocoran memori asli. Masalah umum adalah kebocoran memori asli yang disebabkan oleh tidak menutup ZipInputStream
/GZIPInputStream
.
Sebuah cara umum yang menggunakan ZipInputStream
dibuka adalah dengan panggilan ke Class.getResource
/ClassLoader.getResource
dan memanggil openConnection().getInputStream()
pada java.net.URL
contoh atau dengan memanggil Class.getResourceAsStream
/ClassLoader.getResourceAsStream
. Seseorang harus memastikan bahwa aliran ini selalu ditutup.
Beberapa pustaka sumber terbuka yang umum digunakan memiliki bug yang membocorkan java.util.zip.Inflater
yang tidak tertutup atau java.util.zip.Deflater
contoh. Misalnya, pustaka Nimbus Jose JWT telah memperbaiki kebocoran memori terkait di versi 6.5.1. Java JWT (jjwt) memiliki bug serupa yang diperbaiki pada versi 0.10.7. Pola bug dalam 2 kasus ini adalah fakta yang memanggil DeflaterOutputStream.close()
dan InflaterInputStream.close()
jangan panggil Deflater.end()
/Inflater.end()
ketika sebuah Deflater
/Inflater
contoh disediakan. Dalam kasus tersebut, tidak cukup hanya memeriksa kode untuk aliran yang ditutup. Setiap Deflater
/Inflater
instance yang dibuat dalam kode harus menangani .end()
itu dipanggil.
Salah satu cara untuk memeriksa kebocoran Zip*Stream adalah dengan mendapatkan heap dump dan mencari instance dari kelas apa pun dengan nama "zip", "Inflater", atau "Deflater". Ini dimungkinkan di banyak alat analisis heap dump seperti Yourkit Java Profiler, JProfiler atau Eclipse MAT. Ada baiknya juga memeriksa objek dalam status finalisasi karena dalam beberapa kasus, memori dilepaskan hanya setelah finalisasi. Memeriksa kelas yang mungkin menggunakan perpustakaan asli berguna. Ini juga berlaku untuk pustaka TLS/ssl.
Ada alat OSS yang disebut pemeriksa kebocoran dari Elastic yang merupakan Agen Java yang dapat digunakan untuk menemukan sumber java.util.zip.Inflater
instance yang belum ditutup (.end()
tidak dipanggil).
Untuk kebocoran memori asli secara umum (tidak hanya untuk kebocoran perpustakaan zip), Anda dapat menggunakan jemalloc untuk men-debug kebocoran memori asli dengan mengaktifkan profil pengambilan sampel malloc dengan menentukan pengaturan di MALLOC_CONF
variabel lingkungan. Instruksi terperinci tersedia di posting blog ini:http://www.evanjones.ca/java-native-leak-bug.html . Posting blog ini juga memiliki informasi tentang menggunakan jemalloc untuk men-debug kebocoran memori asli di aplikasi java. Ada juga postingan blog dari Elastic yang menampilkan jemalloc dan menyebutkan pemeriksa kebocoran, alat yang dibuat oleh Elastic untuk melacak masalah yang disebabkan oleh sumber daya zip inflater yang tidak ditutup.
Ada juga posting blog tentang kebocoran memori asli terkait ByteBuffers. Java 8u102 memiliki properti sistem khusus jdk.nio.maxCachedBufferSize
untuk membatasi masalah cache yang dijelaskan dalam posting blog itu.
-Djdk.nio.maxCachedBufferSize=262144
Ini juga baik untuk selalu memeriksa pegangan file yang terbuka untuk melihat apakah kebocoran memori disebabkan oleh sejumlah besar file mmap:ed. Di Linux lsof
dapat digunakan untuk membuat daftar file terbuka dan soket terbuka:
lsof -Pan -p PID
Laporan peta memori dari proses tersebut juga dapat membantu menyelidiki kebocoran memori asli
pmap -x PID
Untuk proses Java yang berjalan di Docker, seharusnya dimungkinkan untuk mengeksekusi perintah lsof atau pmap pada "host". Anda dapat menemukan PID dari proses kemas dengan perintah ini
docker inspect --format '{{.State.Pid}}' container_id
Ini juga berguna untuk mendapatkan thread dump (atau menggunakan jconsole/JMX) untuk memeriksa jumlah utas karena setiap utas menggunakan 1MB memori asli untuk tumpukannya. Sejumlah besar utas akan menggunakan banyak memori.
Ada juga Pelacakan Memori Asli (NMT) di JVM. Itu mungkin berguna untuk memeriksa apakah JVM itu sendiri yang menggunakan memori asli.
Alat jattach dapat digunakan juga di lingkungan kontainer (buruh pelabuhan) untuk memicu threaddump atau heapdump dari host. Itu juga dapat menjalankan perintah jcmd yang diperlukan untuk mengendalikan NMT.