Usamos cookies essenciais para login e armazenamento local para suas preferências. Para métricas de uso, usamos o Google Analytics 4 — você pode recusar sem perder nada do produto. Saber mais

ThreadMineThreadMine
Voltar

Mensagem de erro

java.lang.OutOfMemoryError: unable to create native thread

Resposta rápida

Causa provávelO sistema operacional recusou criar outra thread: leak, limite do processo/container ou memória nativa. Não é o heap: -Xmx maior piora.

Próximo passoConte as threads. O kill -3 imprime o thread dump no stdout da JVM.

Thread dump

kill -3 <pid>
Analisar meu dump agora

A linha do log (JDK 11 em diante)

Exception in thread "http-nio-8080-exec-7" java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
	at java.base/java.lang.Thread.start0(Native Method)
	at java.base/java.lang.Thread.start(Thread.java:1417)
	...

O que a mensagem significa

A JVM pediu uma nova thread ao sistema operacional e o pedido falhou. No Linux, essa chamada é o pthread_create. A JVM relata a falha como um OutOfMemoryError, mas o assunto é o processo, não o heap.

O texto depende do JDK. O JDK 8 imprime unable to create new native thread. O JDK 11, 17 e 25 imprimem unable to create native thread: possibly out of memory or process/resource limits reached. Os dois significam o mesmo.

Duas consequências: um heap dump não mostra a causa, e um -Xmx maior pode deixar o erro mais frequente, porque as stacks das threads ficam fora do heap e o heap tira memória delas.

Causas comuns

  1. Um thread leak. Código que cria um executor, ou uma thread, a cada chamada e nunca o encerra. A contagem de threads cresce até o limite. É a causa mais comum em aplicações que rodaram bem por dias.
  2. O limite de processos do usuário. ulimit -u limita as threads de um usuário, e cada thread conta como um processo nesse limite.
  3. O limite do container. O --pids-limit do Docker, o limite de PIDs do pod no Kubernetes ou o pids.max do cgroup. O limite é do container, então os outros processos dele também contam.
  4. Limites do sistema. kernel.threads-max, kernel.pid_max e vm.max_map_count.
  5. Sem memória nativa. Cada thread de plataforma reserva uma stack (-Xss, 1 MB por padrão no Linux x64). Com threads suficientes, só as stacks usam a memória que o container tem.

Capture a evidência

Primeiro conte as threads e compare com os limites. Rode no mesmo host ou container da JVM:

Contagem de threads e limites

grep Threads /proc/<pid>/status
ulimit -u
cat /sys/fs/cgroup/pids.current /sys/fs/cgroup/pids.max

O campo Threads: em /proc/<pid>/status é o número de threads do processo. Depois tire o dump. No limite, o jstack e o jcmd podem falhar, porque precisam que a JVM crie uma thread para responder. O kill -3 <pid> não precisa: a JVM escreve o thread dump no próprio stdout, então leia no console ou no log do container. Outras formas de capturar: como capturar um thread dump.

Tem o dump? Cole e veja quais nomes de thread se acumulam.

Analisar meu dump agora

Dump com dados sensíveis? Anonimize antes com o tm-anon.

Como aparece no dump

Um thread leak aparece como milhares de threads com a mesma stack e um nome que só incrementa. Este é um dump real da nossa reprodução (JDK 25), em que o código criava um executor novo a cada chamada. Cada thread está ociosa, parada na fila do próprio executor:

Uma das threads ociosas dos pools

"pool-1-thread-1" #26 [54084] prio=5 os_prio=0 cpu=0.00ms elapsed=4.99s tid=0x000000b3ef02c230 nid=54084 waiting on condition  [0x000000b3eafee000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park(java.base@25.0.2/Native Method)
	- parking to wait for  <0x000000060ec0b3a0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(java.base@25.0.2/LockSupport.java:369)
	...
	at java.util.concurrent.LinkedBlockingQueue.take(java.base@25.0.2/LinkedBlockingQueue.java:435)
	at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@25.0.2/ThreadPoolExecutor.java:1016)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@25.0.2/ThreadPoolExecutor.java:1076)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@25.0.2/ThreadPoolExecutor.java:614)
	at java.lang.Thread.runWith(java.base@25.0.2/Thread.java:1487)
	at java.lang.Thread.run(java.base@25.0.2/Thread.java:1474)

O sinal está nos nomes. Cada um é a thread-1 de um pool diferente, 150 pools neste dump:

Nomes no dump

"pool-1-thread-1"
"pool-2-thread-1"
"pool-3-thread-1"
...
"pool-150-thread-1"

O ThreadMine conta as threads pelo prefixo do nome e reporta o padrão:

Crítico

Vazamento de executors: 150 pools de threads separados com nome padrão

150 threads

150 threads pool-N-thread-M em 150 pools. Provavelmente um executor novo é criado a cada chamada e nunca recebe shutdown.

À mão, conte as threads pelo nome sem o número e procure o que domina. Um nome que se repete milhares de vezes é o leak.

Como corrigir

Ache a causa com a contagem e o dump, e corrija essa causa. Mudar limites vem por último.

Encerre o que você cria

Todo executor que você cria precisa de shutdown(). A partir do Java 19 o ExecutorService é AutoCloseable, então o try-with-resources faz isso:

try-with-resources (Java 19+)

try (ExecutorService executor = Executors.newFixedThreadPool(4)) {
    executor.submit(task);
}   // close() waits for the tasks and stops the threads (Java 19+)

Compartilhe um pool limitado

Crie o executor uma vez, como bean ou campo, com tamanho fixo. Não crie um por requisição.

Dê nome às threads

Passe uma ThreadFactory que nomeie as threads pelo que elas fazem. Um leak com nome de verdade se acha com uma olhada no dump, e o pool-N-thread-M esconde quem o criou.

Aumente o limite por último

Aumente o ulimit -u, o limite de PIDs do container ou os limites do sistema só depois de descartar um leak. Com um leak, um limite maior só adia o mesmo erro. Se a contagem é alta e legítima, reduza o -Xss ou o tamanho dos pools antes de aumentar qualquer coisa.

Mais sobre ler o dump de uma aplicação travada: Spring Boot stuck threads.

Perguntas frequentes

"unable to create native thread" é problema de heap?

Não. O heap ainda tem espaço. A JVM pediu uma nova thread ao sistema operacional (pthread_create no Linux) e a chamada falhou. Um heap dump não ajuda, e um -Xmx maior deixa menos memória para as stacks das threads, então pode deixar o erro mais frequente.

Qual a diferença entre "unable to create new native thread" e "unable to create native thread"?

Só o texto. O JDK 8 imprime "unable to create new native thread". O JDK 11, 17 e 25 imprimem "unable to create native thread: possibly out of memory or process/resource limits reached". A causa é a mesma, então as mesmas correções valem.

Por que o jstack falha quando isso acontece?

O jstack e o jcmd se conectam à JVM por uma thread auxiliar, e no limite a JVM pode não conseguir criá-la. O kill -3 <pid> não precisa se conectar: a JVM imprime o thread dump no próprio stdout, então procure no console ou no log do container.

Quantas threads uma JVM aguenta?

Não há um número fixo. O limite é o primeiro que for atingido entre: o limite de processos do usuário (ulimit -u), o limite de PIDs do container, os limites do sistema (threads-max, pid_max, vm.max_map_count) e a memória nativa que sobra para as stacks, aproximadamente o tamanho da stack (-Xss) vezes o número de threads. Um serviço saudável raramente precisa de milhares de threads de plataforma.

Como vejo o limite de threads do meu container?

Dentro do container, cat /sys/fs/cgroup/pids.max mostra o limite e pids.current a contagem atual (cgroup v2). O Docker define com --pids-limit, e o Kubernetes com o limite de PIDs do pod. Se o pids.current está perto do pids.max, o limite do container é o que você atingiu.

Tem o dump da JVM no limite?

Cole e veja quais nomes de thread se acumulam. Sem cadastro para o primeiro dump.