Cosa consuma memoria nel processo Java?


20

stiamo provando a studiare l'utilizzo della memoria del processo java sotto carico moderato.

  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

Come puoi vedere, abbiamo una memoria residente a 6Gb. Ora la parte interessante è questa: il processo viene eseguito con questi parametri:

  • -Xmx2048m
  • -Xms2048m
  • -XX: newSize = 512m
  • -XX: MaxDirectMemorySize = 256m
  • ... altri per GC e cose del genere

Osservando queste impostazioni e l'utilizzo effettivo della memoria, siamo incapaci di vedere la differenza tra ciò che prevediamo che questo processo stia utilizzando e ciò che effettivamente utilizza.

Di solito i nostri problemi di memoria vengono risolti analizzando il dump dell'heap, ma in questo caso la nostra memoria viene utilizzata da qualche parte al di fuori dell'heap.

Domande: quali sarebbero i passaggi per provare a trovare il motivo di un utilizzo della memoria così elevato? Quali strumenti potrebbero aiutarci a identificare ciò che utilizza la memoria in quel processo?

MODIFICA 0

Non sembra che questo sia un problema legato all'heap in quanto abbiamo ancora abbastanza spazio lì:

jmap -heap 12663

risulta in (modificato per risparmiare spazio)

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

MODIFICA 1

usando la pmap possiamo vedere che ci sono abbastanza quantità di allocazioni di 64 Mb:

pmap -x 12663 | grep rwx | sort -n -k3 | less

risulta in:

... 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 ?

Quindi, come scoprire quali sono quei pezzi da 64 Mb? Cosa li sta usando? Che tipo di dati sono in essi?

Grazie


2
Ho avuto esattamente lo stesso problema ... ecco la mia domanda. stackoverflow.com/questions/18734389/… Hai una soluzione al riguardo?
DeepNightDue

Risposte:


21

Il problema potrebbe essere correlato a questo problema glibc .

Fondamentalmente, quando si hanno più thread che allocano memoria, glibc scalerà il numero di arene disponibili da cui eseguire l'allocazione per evitare contese di blocco. Un'arena è grande 64 Mb. Il limite superiore è quello di creare 8 volte il numero di arene core. Le arene verranno create su richiesta quando un thread accede a un'arena già bloccata in modo che cresca nel tempo.

In Java, dove si cospargono i thread, ciò può portare rapidamente alla creazione di molte arene. E ci sono allocazioni sparse in tutte queste arene. Inizialmente ogni arena da 64 Mb è solo mappata memoria senza commit, ma mentre esegui le allocazioni inizi a utilizzare la memoria effettiva per esse.

La tua pmap probabilmente avrà elenchi simili a questo di seguito. Notare come 324K + 65212K = 65536K, 560K + 64976K == 65536K, 620K + 64916K == 65536K. Cioè, si sommano fino a 64 Mb.

00007f4394000000 324K rw --- [anon]
00007f4394051000 65212K ----- [anon]
00007f4398000000 560K rw --- [anon]
00007f439808c000 64976K ----- [anon]
00007f439c000000 620K rw --- [anon]
00007f439c09b000 64916K ----- [anon]

Per quanto riguarda le soluzioni alternative : il bug menziona alcuni parametri di ambiente che puoi impostare per limitare il numero di arene, ma hai bisogno di una versione glibc abbastanza alta.


5
impostando Xmx e Xms sullo stesso valore, oltre a impostare la variabile di ambiente "export MALLOC_ARENA_MAX = 4" nello script sh che avvia il nostro servizio web ci ha aiutato nel nostro caso. In precedenza, si verificavano riavvii del servizio Web dovuti a OOM Killer ogni 2-8 ore. La versione GLIBC in Ubuntu 14.04 è la 2.19 che è buona, poiché deve essere> = 2.16 per far funzionare l'impostazione
MALLOC_ARENA_MAX

Questa risposta e il commento sopra sono stati per me un salvavita. Nel mio caso MALLOC_ARENA_MAX = 1 era necessario ed efficace.
John Bachir,

3

Che ne dici di Lamdba Probe ? Tra le altre cose, può mostrare suddivisioni dell'utilizzo della memoria simili allo screenshot seguente:

Visualizzazione dell'utilizzo della memoria della sonda lambda

A volte pmap -x your_java_pidpuò anche essere utile.


Grazie per la tua risposta. Se ho capito bene allora Lambda Probe è per Apache Tomcat? Che non usiamo ... Per quanto riguarda la pmap, aggiungerò le informazioni al primo messaggio
Konstantin S.

2

JProfiler potrebbe essere qualcosa che cerchi ma non è gratuito. Un altro strumento valido e gratuito per studiare l'utilizzo della memoria del processo java è Java VisualVM disponibile come strumento JDK nelle distribuzioni Oracle / Sun JDK. Personalmente consiglierei un approccio più olistico al problema (cioè per monitorare i dischi JDK + OS + +, ecc.) - l'uso di alcuni sistemi di monitoraggio della rete - Nagios, Verax NMS o OpenNMS.


2
La sua perdita è fuori dal comune, quindi JProfiler non sarà di grande aiuto qui
Asaf Mesika,

2

Il problema è al di fuori dell'heap, quindi i migliori candidati sono:

JNI leak  
Allocation of direct memory buffer

A causa del fatto che hai limitato la dimensione del buffer diretto, il miglior candidato secondo me è la perdita di JNI.


1

Esiste uno strumento utile per visualizzare l'allocazione della memoria heap inclusa nel JDK chiamato jmap, oltre a questo hai anche stack etc (Xss). Esegui questi due comandi jmap per ottenere maggiori informazioni sull'utilizzo della memoria:

jmap -heap <PID>
jmap -permstat <PID>

Per ottenere ancora più informazioni è possibile connettersi al processo con jconsole (incluso anche nel JDK). Jconsole richiede tuttavia che JMX sia configurato nell'applicazione.


Grazie per la risposta, ma il problema sembra essere da qualche parte fuori dall'heap. Aggiornerò il primo post per riflettere alcune informazioni di jmap
Konstantin S.

Quanti thread ha il processo? La dimensione dello stack è 2 MB di default sulla maggior parte delle piattaforme, quindi moltiplicalo per il numero di thread. Sarei sorpreso se spiegasse tutta la memoria "mancante", ma forse anche una parte.
HampusLi

Circa 300 thread, presi da pmap, abbiamo una dimensione dello stack di 1 Mb. E dalla stessa uscita pmap non sembra che nessuna di quelle pile usi più di 100Kb
Konstantin S.

0

Usa JVisualVM. Ha diverse visualizzazioni che ti diranno quanta memoria heap è in uso, PermGen e così via.

Per quanto riguarda la risposta alla tua domanda. Java gestisce la memoria in modo molto diverso da quello che ci si potrebbe aspettare.

Quando si impostano i parametri -Xms e -Xmx, si indica alla JVM la quantità di memoria che dovrebbe allocare nell'heap per iniziare e anche la quantità da allocare al massimo.

Se si dispone di un'applicazione Java che utilizzava un totale di 1 m di memoria ma passava in -Xms256m -Xmx2g, la JVM si inizializza automaticamente con 256 m di memoria utilizzata. Non userà meno di quello. Non importa che l'applicazione utilizzi solo 1 m di memoria.

In secondo luogo. Nel caso precedente, se l'app ad un certo punto utilizza più di 256 m di memoria, la JVM allocherà tutta la memoria necessaria per soddisfare la richiesta. Tuttavia, non ridurrà la dimensione dell'heap al valore minimo. Almeno, non nella maggior parte dei casi.

Nel tuo caso, poiché stai impostando la memoria minima e massima su 2 g, la JVM assegnerà 2 g all'inizio e la manterrà.

La gestione della memoria Java è piuttosto complessa e l'ottimizzazione dell'utilizzo della memoria può essere un'attività in sé. Ci sono tuttavia molte risorse là fuori che possono aiutare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.