kami mencoba untuk menyelidiki penggunaan memori proses java di bawah beban sedang.
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12663 test 20 0 8378m 6.0g 4492 S 43 8.4 162:29.95 java
Seperti yang Anda lihat kami memiliki memori penduduk di 6Gb. Sekarang bagian yang menarik adalah ini: proses dijalankan dengan params ini:
- -Xmx2048m
- -Xms2048m
- -XX: NewSize = 512m
- -XX: MaxDirectMemorySize = 256m
- ... beberapa lainnya untuk GC dan lainnya
Melihat pengaturan ini dan penggunaan memori yang sebenarnya, kami tersandung untuk melihat perbedaan dari apa yang kami harapkan akan digunakan oleh proses ini dan apa yang sebenarnya digunakan.
Biasanya masalah ingatan kita diselesaikan dengan menganalisis heap dump tetapi dalam kasus ini ingatan kita digunakan di suatu tempat di luar heap.
Pertanyaan: Apa langkah-langkah untuk mencoba dan menemukan alasan penggunaan memori yang sedemikian tinggi? Alat apa yang dapat membantu kami mengidentifikasi apa yang menggunakan memori dalam proses itu?
EDIT 0
Sepertinya ini bukan masalah yang berhubungan dengan tumpukan karena kita masih memiliki beberapa ruang di sana:
jmap -heap 12663
hasil dalam (diedit untuk menghemat ruang)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 536870912 (512.0MB)
MaxNewSize = 536870912 (512.0MB)
OldSize = 1610612736 (1536.0MB)
NewRatio = 7
SurvivorRatio = 8
PermSize = 21757952 (20.75MB)
MaxPermSize = 85983232 (82.0MB)
New Generation: 45.7% used
Eden Space: 46.3% used
From Space: 41.4% used
To Space: 0.0% used
concurrent mark-sweep generation: 63.7% used
Perm Generation: 82.5% used
EDIT 1
menggunakan pmap kita dapat melihat bahwa ada sejumlah alokasi 64Mb:
pmap -x 12663 | grep rwx | sort -n -k3 | less
menghasilkan:
... a lot more of these 64Mb chunks
00007f32b8000000 0 65508 65508 rwx-- [ anon ] <- what are these?
00007f32ac000000 0 65512 65512 rwx-- [ anon ]
00007f3268000000 0 65516 65516 rwx-- [ anon ]
00007f3324000000 0 65516 65516 rwx-- [ anon ]
00007f32c0000000 0 65520 65520 rwx-- [ anon ]
00007f3314000000 0 65528 65528 rwx-- [ anon ]
00000000401cf000 0 241904 240980 rwx-- [ anon ] <- Direct memory ?
000000077ae00000 0 2139688 2139048 rwx-- [ anon ] <- Heap ?
Jadi bagaimana cara mengetahui potongan 64Mb itu? Apa yang menggunakannya? Jenis data apa yang ada di dalamnya?
Terima kasih
Jawaban:
Masalahnya mungkin terkait dengan masalah glibc ini .
Pada dasarnya, ketika Anda memiliki banyak utas yang mengalokasikan memori, glibc akan meningkatkan jumlah arena yang tersedia untuk melakukan alokasi dari untuk menghindari pertikaian kunci. Arena berukuran 64 MB. Batas atas adalah membuat 8 kali jumlah arena inti. Arena akan dibuat sesuai permintaan ketika utas mengakses arena yang sudah dikunci sehingga berkembang seiring waktu.
Di Jawa tempat Anda menaburi utas, ini dapat dengan cepat menyebabkan banyak arena dibuat. Dan ada alokasi yang tersebar di seluruh arena ini. Awalnya setiap arena 64Mb hanya memetakan memori yang tidak terhubung, tetapi saat Anda mengalokasikan Anda mulai menggunakan memori aktual untuknya.
Pmap Anda mungkin memiliki daftar yang mirip dengan di bawah ini. Perhatikan bagaimana 324K + 65212K = 65536K, 560K + 64976K == 65536K, 620K + 64916K == 65536K. Artinya, jumlah mereka hingga 64Mb.
Adapun solusinya : Bug menyebutkan beberapa parameter lingkungan yang dapat Anda atur untuk membatasi jumlah arena, tetapi Anda memerlukan versi glibc yang cukup tinggi.
sumber
Bagaimana dengan Probe Lamdba ? Di antara hal-hal lain itu dapat menunjukkan kerusakan penggunaan memori yang mirip dengan tangkapan layar di bawah ini:
Terkadang
pmap -x your_java_pid
juga bisa membantu.sumber
JProfiler bisa menjadi sesuatu yang Anda cari tetapi tidak gratis. Alat lain yang bagus dan gratis untuk menyelidiki penggunaan memori proses java adalah Java VisualVM yang tersedia sebagai alat JDK dalam distribusi Oracle / Sun JDK. Saya pribadi merekomendasikan pendekatan yang lebih holistik untuk masalah ini (yaitu untuk memonitor disk JDK + OS +, dll) - penggunaan beberapa sistem pemantauan jaringan - Nagios, Verax NMS atau OpenNMS.
sumber
Masalahnya adalah di luar tumpukan, jadi kandidat terbaik adalah:
Karena Anda telah membatasi ukuran buffer langsung, kandidat terbaik menurut saya adalah kebocoran JNI.
sumber
Ada alat yang berguna untuk melihat alokasi memori heap termasuk dalam JDK disebut jmap, di atas ini Anda juga memiliki tumpukan dll (Xss). Jalankan kedua perintah jmap ini untuk mendapatkan informasi lebih lanjut tentang penggunaan memori:
Untuk mendapatkan lebih banyak informasi lebih lanjut Anda dapat terhubung ke proses dengan jconsole (juga termasuk dalam JDK). Namun Jconsole memerlukan JMX untuk dikonfigurasikan dalam aplikasi.
sumber
Gunakan JVisualVM. Ini memiliki berbagai pandangan yang berbeda yang akan memberi tahu Anda berapa banyak memori tumpukan yang digunakan, PermGen dan seterusnya.
Adapun untuk menjawab pertanyaan Anda. Java menangani memori dengan sangat berbeda dari yang Anda harapkan.
Ketika Anda mengatur parameter -Xms dan -Xmx, Anda memberi tahu JVM berapa banyak memori yang harus dialokasikan di heap untuk memulainya dan juga berapa banyak yang seharusnya dialokasikan sebagai maksimum.
Jika Anda memiliki aplikasi java yang menggunakan total memori 1m tetapi melewati -Xms256m -Xmx2g maka JVM akan menginisialisasi dirinya dengan 256m memori yang digunakan. Itu tidak akan menggunakan kurang dari itu. Tidak masalah bahwa aplikasi Anda hanya menggunakan memori 1m.
Kedua. Dalam kasus di atas, jika aplikasi Anda pada titik tertentu menggunakan lebih dari 256m memori, JVM akan mengalokasikan memori sebanyak yang diperlukan untuk melayani permintaan. Namun, itu tidak akan menurunkan ukuran tumpukan kembali ke nilai minimum. Setidaknya, tidak dalam sebagian besar keadaan.
Dalam kasus Anda, karena Anda menetapkan memori minimum dan maksimum pada 2g, JVM akan mengalokasikan 2g di awal dan memeliharanya.
Manajemen memori Java cukup rumit dan menyetel penggunaan memori dapat menjadi tugas tersendiri. Namun, ada banyak sumber daya di luar sana yang dapat membantu.
sumber