Java : Lado do SO ‘ Out of memory : unable to create new native thread’

Neste post será apresentado como investigar o problema de ‘ Out of memory : unable to create new native thread’ do lado do sistema operacional .

1) Causa :

Por algum motivo a aplicação para e é apresentado o erro abaixo :

Caused by: java.lang.OutOfMemoryError: unable to create new native thread
      at java.lang.Thread.start0(Native Method)
      at java.lang.Thread.start(Thread.java:714)
      at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:949)
      at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1371)

Às vezes por causa do limite imposto no sistema operacional Linux / Unix a aplicação não consegue abrir mais processos e com isso tomamos este erro, sendo assim parando a aplicação e reiniciar a JVM não seria uma melhor solução , pois devido a limitação no SO o problema ocorrerá novamente.

threads3

2) Análise no Sistema Operacional :

Por padrão cada usuário no SO já com o Max Files limitado para 1024 threads.

Quando é apresentado em específico entramos no usuário da aplicação e rodamos o comando para ver o número de threads :

su - appuser
ulimit -a 

Segue um exemplo de um log de Jboss quando é apresentado o problema :

threads2

Para definirmos o valor ideal para que o usuário da aplicação tenha o valor o ideal para rodar sem problemas :

* Verificamos o valor total que o sistema operacional suporta /proc/sys/fs/file-max :

threadas1

* Após chegar ao valor obtido incluímos os valores abaixo no arquivo /etc/security/limits.conf :

appuser           soft    nofile     30000
appuser         hard    nofile     30000
appuser         soft   nproc       30000
appuser         hard    nproc      30000

* Monitoramos a solução com o script no link :

Script : Monitorando processos abertos pelo usuário no SO

No exemplo abaixo altere o APPUSER nas variáveis pelo usuário que o appserver usa :

#!/bin/bash
threads=" `ps h -Led -o user | sort | uniq -c | sort -n | grep APPUSER | awk '{print $1}'`"
processo="`pgrep -fl APPUSER | head -n1 | awk '{print $1}'`"


echo $"Numeros de threads criadas pelo usuario APPUSER -->  `echo $threads`"
echo ""
echo ""
echo $"Processo que o APPUSER esta usando -->  `echo $processo`"
echo ""
echo ""
echo "Valor do usuario do  APPUSER em  /etc/security/limits.conf"

runuser -l appuser -c 'ulimit -a | grep "max user processes"'

Com esta análise já podemos acompanhar a aplicação no lado do Sistema Operacional.

* Aumentando o valor total de threads de SO :

Não é recomendado que seja configurado diretamente o no Kernel este o valor total em um servidor em produção , caso seja uma aplicação de alto desempenho , é sugerido que se faça diversos testes antes de ir para a produção sem haver mudanças bruscas.

Caso seja necessário alterar a nível total de SO , podemos aumentar seguindo os passos :

Inclua os valores no final do arquivo /etc/sysctl.conf :

# Controls the maximum number of threads
kernel.threads-max = 200000

Para iniciar os valores rode o comando :

sysctl -p 

Referências :

https://access.redhat.com/documentation/en-US/Red_Hat_Directory_Server/8.2/html/Performance_Tuning_Guide/system-tuning.html

https://support.adeptia.com/entries/21540822-Steps-to-resolve-unable-to-create-new-native-thread-issue-on-Linux-