Per le applicazioni container, è difficile individuare i problemi derivanti dall’eccessivo consumo di memoria. Nel caso in cui l’uso superi il limite di memoria del container, un’applicazione può fallire silenziosamente senza lasciare alcuna traccia.
In questo articolo, esplorerò alcune delle tecniche che possono essere utilizzate per identificare la fonte del consumo di memoria in un’applicazione container Java.
Tipo di Memoria
In un tipico applicazione Java, la memoria può essere ampiamente suddivisa in heap e non-heap. La memoria heap può essere impostata fornendo i parametri JVM pertinenti al momento di avviare qualsiasi applicazione Java.
La memoria non-heap consiste in memoria nativa utilizzata dal JVM stesso o da qualsiasi libreria utilizzata all’interno dell’applicazione tramite JNI (Java Native Interface).
Metodo
Per la memoria heap, è possibile prendere un dump heap e analizzarlo utilizzando strumenti di analisi del dump heap. Uno dei migliori strumenti per l’analisi del dump heap è l’eclipse MAT.
Java fornisce un meccanismo per tracciare l’allocazione di memoria nativa abilitando il tracciamento della memoria nativa, ma potrebbe non rivelare tutta la memoria allocata da librerie native.
Jemalloc è un utilità che può essere utilizzata per tracciare la memoria allocata dalle librerie native. La memoria nativa viene allocata utilizzando un allocatore di memoria predefinito chiamato malloc. Jemalloc è un’implementazione generica di malloc con la quale è possibile abilitare il monitoraggio dell’allocazione della memoria. Traccia tutta l’allocazione di memoria nativa e genera dump di profili dell’heap.
Questi profili dell’heap possono quindi essere analizzati utilizzando l’utilità Jeprof. Jeprof genera il rapporto di allocazione dell’heap, evidenziando la memoria utilizzata dalle funzioni nell’applicazione.
Analisi
Di seguito è riportata un’analisi della memoria di un’applicazione container Java di esempio. L’applicazione carica un modello di esempio Tensorflow per abilitare l’utilizzo della memoria nativa e viene eseguita in un contenitore Docker.
Di seguito è riportato il consumo di memoria di Docker. Mostra 254MB. Proviamo a individuare la fonte del consumo di memoria.
Memoria Totale
Per avere un’idea della memoria totale utilizzata dal processo dell’applicazione, possiamo controllare la Dimensione del Set Residente (RSS). È la memoria complessivamente impegnata che risiede nella memoria principale o RAM. Esistono diverse utilità che possono aiutare a controllare questo come top, ps o pmap.
Verifica dell’RSS non aiuta a identificare la fonte principale dell’uso. Per l’applicazione di esempio, utilizzando il comando sottostante, il totale dell’RSS è di 376MB.
ps --no-header -o rss $(pidof java)
Analisi dell’Heap
Di seguito è riportato il consumo di memoria heap come generato dall’outil di Eclipse MAT. La memoria heap totale trattenuta è indicata come 2,2MB, che è molto al di sotto del consumo totale di memoria mostrato da Docker e indica che la maggior parte del consumo proviene dall’area non heap.
Analisi della Memoria Nativa
Rivedendo il riepilogo della memoria nativa utilizzando il comando sottostante, l’uso totale della memoria sembra essere circa 99MB. Tuttavia, questo valore è inferiore al consumo totale di memoria e non identifica accuratamente la causa principale del problema.
jcmd $(pidof java) VM.native_memory \
| grep -P "Total.*committed=" \
| grep -o -P "(?<=committed=)[0-9]+(?=KB)"
Analisi della Memoria Fuori Heap
Un’analisi utilizzando Jemalloc e Jeprof rivela che l’uso della memoria nativa è principalmente attribuito alla libreria Tensorflow, con un consumo totale di circa 112MB.
Questa intuizione fornisce un chiaro indizio sulla fonte dell’uso della memoria nativa e può essere ulteriormente investigata per minimizzare qualsiasi consumo eccessivo.
Conclusione
L’analisi della memoria Java è critica, soprattutto per le applicazioni basate su container. Conoscere la fonte del consumo di memoria in un’applicazione può aiutarci a capire i requisiti di memoria e ridurre i costi dell’applicazione rimuovendo qualsiasi consumo inutile.
Quando si controlla il consumo di memoria, è necessario identificare tutti i tipi di memoria e le loro fonti. L’analisi del dump heap può identificare le fonti del consumo di memoria heap, e Jemalloc e Jeprof sono utili per identificare le fonti del consumo di memoria nativa.
Link al Codice Applicazione di Esempio
Source:
https://dzone.com/articles/java-container-application-memory-analysis