Para aplicações em contêineres, é difícil identificar problemas decorrentes do excesso de uso de memória. Caso o uso ultrapasse o limite de memória do contêiner, uma aplicação pode falhar silenciosamente sem deixar qualquer vestígio.
Neste artigo, vou abordar algumas técnicas que podem ser utilizadas para identificar a origem do consumo de memória em uma aplicação em contêiner Java.
Tipo de Memória
Em um aplicativo Java típico, a memória pode ser amplamente dividida em heap e não-heap. A memória heap pode ser configurada fornecendo parâmetros relevantes do JVM ao iniciar qualquer aplicativo Java.
A memória não-heap consiste em memória nativa usada pelo próprio JVM ou por qualquer biblioteca usada dentro do aplicativo que utiliza a JNI (Java Native Interface).
Método
Para a memória heap, pode-se realizar um heap dump e analisá-lo usando ferramentas de análise de heap dump. Uma das melhores ferramentas para análise de heap dump é o eclipse MAT.
O Java fornece um mecanismo para rastrear a alocação de memória nativa ativando o rastreamento de memória nativa, mas isso pode não revelar toda a memória alocada por bibliotecas nativas.
Jemalloc é uma ferramenta que pode ser usada para rastrear a memória alocada por bibliotecas nativas. A memória nativa é alocada usando um alocador de memória padrão chamado malloc. Jemalloc é uma implementação de malloc de uso geral na qual a rastreabilidade da alocação de memória pode ser habilitada. Ela rastreia toda a alocação de memória nativa e gera dumps de perfil de heap.
Esses perfis de heap podem então ser analisados usando a Jeprof utility. Jeprof gera o relatório de alocação de heap, destacando a memória usada por funções no aplicativo.
Análise
Abaixo está uma análise de memória de um aplicativo de contêiner Java de exemplo. O aplicativo carrega um modelo de Tensorflow de exemplo para habilitar a utilização de memória nativa e roda em um contêiner Docker.
Abaixo está o consumo de memória do Docker. Ele mostra 254MB. Vamos tentar identificar a fonte do consumo de memória.
Memória Total
Para ter uma noção da memória total sendo usada pelo processo do aplicativo, podemos verificar o Resident Set Size (RSS). É a memória total comprometida que reside na memória principal ou RAM. Existem várias utilidades que podem ajudar a verificar isso como top, ps ou pmap.
Verificar o RSS não ajuda a identificar a fonte raiz do consumo. Para o aplicativo de exemplo, ao usar o comando abaixo, o RSS total é de 376MB.
ps --no-header -o rss $(pidof java)
Análise do Heap
Abaixo está o consumo de memória heap gerado pela ferramenta Eclipse MAT. O heap retido total é mostrado como 2,2MB, que está muito abaixo do consumo total de memória mostrado pelo Docker e indica que a maioria do consumo vem da área não heap.
Análise de Memória Nativa
Ao rever o resumo da memória nativa usando o comando abaixo, o uso total de memória parece ser aproximadamente 99MB. No entanto, este valor é menor do que o consumo total de memória e não identifica com precisão a causa raiz do problema.
jcmd $(pidof java) VM.native_memory \
| grep -P "Total.*committed=" \
| grep -o -P "(?<=committed=)[0-9]+(?=KB)"
Análise de Memória Off-Heap
Uma análise usando Jemalloc e Jeprof revela que o uso de memória nativa é principalmente atribuído à biblioteca Tensorflow, com um consumo total de aproximadamente 112MB.
Esta informação fornece uma indicação clara da fonte do uso de memória nativa e pode ser investigada ainda mais para minimizar qualquer consumo excessivo.
Conclusão
A análise de memória Java é crítica, especialmente para aplicativos baseados em containers. Saber a fonte do consumo de memória em um aplicativo pode ajudar a entender os requisitos de memória e reduzir os custos do aplicativo removendo o consumo desnecessário.
Ao verificar o consumo de memória, todas as tipos de memória e suas fontes precisam ser identificadas. A análise de dump de heap pode identificar as fontes de consumo de memória heap, e Jemalloc e Jeprof são úteis na identificação das fontes de consumo de memória nativa.
Link de Código de Aplicação de Exemplo
Source:
https://dzone.com/articles/java-container-application-memory-analysis