“Java.lang.OutOfMemoryError: não foi possível criar um novo thread nativo”

124

Estamos recebendo "java.lang.OutOfMemoryError : unable to create new native Thread"na VM de 8 GB de RAM após 32k threads (ps -eLF | grep -c java)

No entanto "top" and "free -m" shows 50% free memory available,. O JDk é de 64 bits e tentou com o HotSpot e o JRockit.Server com o Linux 2.6.18

Também tentamos OS stack size (ulimit -s)ajustar e os limites máximos de processo (ulimit -u), limit.conf aumentam, mas todos em vão.

Também tentamos quase todas as combinações possíveis de tamanho de pilha, mantendo-a baixa, alta etc.

O script que usamos para executar o aplicativo é

/opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m -Xss128k -jar JavaNatSimulator.jar /opt/tools/jnatclients/natSimulator.properties

Obrigado pela resposta.

Tentamos editar o arquivo /etc/security/limits.conf e ulimit, mas ainda assim

[root@jboss02 ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 72192
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 72192
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
Deepak Tewani
fonte
11
Os sistemas operacionais têm limites no número de threads que você pode criar. Por que você está criando mais de 32k threads? Provavelmente, seu sistema não possui milhares de núcleos de processador, criando tantos threads não é útil. Use um conjunto de threads ( ExecutorService).
Jesper
Obrigado pela resposta. Estamos usando uma biblioteca de código aberto e tentando carregar isso. Qualquer biblioteca de código aberto está criando tantos threads. Mas o que eu não entendo, é quando "top" está mostrando 50% de memória livre, então por que o OutOfMemory Error.
Deepak Tewani
A biblioteca open source que estamos usando em ICE4j Biblioteca
Deepak Tewani
11
OutOfMemoryError não significa necessariamente que o espaço de heap ou RAM "geral" foi esgotada. Nesse caso, fica claro que a falha ocorreu porque o sistema operacional não possui recursos para alocar um encadeamento extra. Ter 50% de memória livre é irrelevante para essa falha específica.
Andrzej Doyle 28/05
1
Quais são os outros recursos necessários para criar novos threads. Ficamos com a impressão de que, se aumentarmos a RAM, poderemos criar mais threads. Por favor, nos guie
Deepak Tewani

Respostas:

80

Esse não é um problema de memória, embora o nome da exceção o sugira, mas um problema de recurso do sistema operacional. Você está ficando sem threads nativos, ou seja, quantos threads o sistema operacional permitirá que sua JVM use.

Esse é um problema incomum, porque você raramente precisa disso. Você tem muitas criações incondicionais de encadeamentos onde os encadeamentos devem, mas não terminam?

Você pode reescrever o uso de Callable / Runnables sob o controle de um Executor, se possível. Existem muitos executores padrão com vários comportamentos que seu código pode controlar facilmente.

(Existem muitas razões pelas quais o número de encadeamentos é limitado, mas eles variam de sistema operacional para sistema operacional)

Thorbjørn Ravn Andersen
fonte
Obrigado pela resposta. Estamos usando uma biblioteca de código aberto ICE4j e tentando carregar isso. Não é possível aumentar o limite de threads no sistema operacional quando sabemos que há 50% de memória restante no servidor.
Deepak Tewani
Possivelmente, mas acho que não irá ajudá-lo como tal. Se você ficar sem recursos durante o teste de carga, precisará controlar o que acontece no seu aplicativo. Por que você tem 32000 threads ativos ao mesmo tempo?
Thorbjørn Ravn Andersen
Estamos criando clientes 11K que usam 32 K threads para leitura e gravação de dados em soquetes UDP. Fora destes 32 K tópicos, 10K tópicos são manter tópicos vivas que são usados para manter o soquete aberto
Deepak Tewani
Acredito que esse problema seja resolvido em servidores web modernos. O udp também pode perder pacotes - qualquer motivo para você não usar apenas um servidor web?
Thorbjørn Ravn Andersen
7
Porque a exceção OutOfMemory deveria ter sido nomeada OutOfResources. O sistema operacional não pode fornecer o recurso necessário. (E aconteceu que eu não sabia ice4j) #
Thorbjørn Ravn Andersen
14

Encontrei o mesmo problema durante o teste de carga, o motivo é que a JVM não conseguiu criar um novo encadeamento Java. Abaixo está o código fonte da JVM

if (native_thread->osthread() == NULL) {    
// No one should hold a reference to the 'native_thread'.    
    delete native_thread;   
if (JvmtiExport::should_post_resource_exhausted()) {      
    JvmtiExport::post_resource_exhausted(        
        JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | 
        JVMTI_RESOURCE_EXHAUSTED_THREADS, 
        "unable to create new native thread");    
    } THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "unable to create new native thread");  
} Thread::start(native_thread);`

Causa raiz: A JVM lança essa exceção quando JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR (recursos esgotados (significa memória esgotada)) ou JVMTI_RESOURCE_EXHAUSTED_THREADS (Threads esgotados).

No meu caso, o Jboss está criando muitos threads, para atender à solicitação, mas todos os threads estão bloqueados. Por esse motivo, a JVM se esgota com threads e também com memória (cada thread contém memória, que não é liberada, porque cada thread está bloqueado).

Analisados ​​os despejos de encadeamento java observados, quase os encadeamentos de 61K são bloqueados por um de nosso método, o que está causando esse problema. Abaixo está a parte do despejo de segmento

"SimpleAsyncTaskExecutor-16562" #38070 prio=5 os_prio=0 tid=0x00007f9985440000 nid=0x2ca6 waiting for monitor entry [0x00007f9d58c2d000]
   java.lang.Thread.State: BLOCKED (on object monitor)
Madhu Cheepati
fonte
Como o método estava bloqueando? Nunca voltando?
Thorbjørn Ravn Andersen
8

É provável que seu sistema operacional não permita o número de threads que você está tentando criar ou esteja atingindo algum limite na JVM. Especialmente se for um número redondo como 32k, um limite de um tipo ou outro é provavelmente o culpado.

Tem certeza de que realmente precisa de threads de 32k? A maioria das linguagens modernas tem algum tipo de suporte para conjuntos de threads reutilizáveis ​​- eu tenho certeza que o Java também tem algo em vigor (como o ExecutorServiceusuário Jesper mencionou). Talvez você possa solicitar threads desse pool, em vez de criar manualmente novos.

Theodoros Chatzigiannakis
fonte
1
Obrigado pela resposta Estamos usando uma biblioteca de código aberto ICE4j e tentando carregar isso. Não é possível aumentar o limite de threads no sistema operacional quando sabemos que há 50% de memória restante no servidor.
Deepak Tewani
1
Estamos criando clientes 11K que usam 32 K threads para leitura e gravação de dados em soquetes UDP. Fora destes 32 K tópicos, 10K tópicos são manter tópicos vivas que são usados para manter o soquete aberto
Deepak Tewani
7

Eu recomendaria também verificar o tamanho da pilha de threads e ver se você criou mais threads. O tamanho da pilha de encadeamentos padrão para o JRockit 1.5 / 1.6 é 1 MB para a VM de 64 bits no sistema operacional Linux. Os threads de 32K exigirão uma quantidade significativa de memória física e virtual para atender a esse requisito.

Tente reduzir o tamanho da pilha para 512 KB como ponto de partida e veja se isso ajuda a criar mais threads para seu aplicativo. Também recomendo explorar o dimensionamento horizontal, por exemplo, dividindo o processamento do aplicativo em mais máquinas físicas ou virtuais.

Ao usar uma VM de 64 bits, o limite verdadeiro dependerá da disponibilidade da memória física e virtual do SO e dos parâmetros de ajuste do SO, como ulimitc. Também recomendo o seguinte artigo como referência:

OutOfMemoryError: não é possível criar um novo encadeamento nativo - Problema desmistificado

PH
fonte
5

Se a jvm for iniciada via systemd, pode haver um limite de maxTasks por processo (as tarefas realmente significam encadeamentos) em alguns sistemas operacionais Linux.

Você pode verificar isso executando "status do serviço" e verifique se há um limite de maxTasks. Se houver, você pode removê-lo editando /etc/systemd/system.conf, adicionando uma configuração: DefaultTasksMax = infinity

Clement.Xu
fonte
3

Eu tive o mesmo problema devido a processos fantasmas que não apareciam ao usar o top no bash. Isso impediu a JVM de gerar mais encadeamentos.

Para mim, ele resolveu ao listar todos os processos java com jps (basta executar jpsno seu shell) e os matou separadamente, usando o kill -9 pidcomando bash para cada processo fantasma.

Isso pode ajudar em alguns cenários.

mac7
fonte
2

Você tem a chance de enfrentar java.lang.OutOfMemoryError: Unable to create new native threadsempre que a JVM solicitar um novo encadeamento no sistema operacional. Sempre que o sistema operacional subjacente não puder alocar um novo encadeamento nativo, esse OutOfMemoryError será lançado. O limite exato para encadeamentos nativos depende muito da plataforma, portanto, é recomendável descobrir esses limites executando um teste semelhante ao exemplo de link abaixo. Mas, em geral, a situação causadora java.lang.OutOfMemoryError: Unable to create new native threadpassa pelas seguintes fases:

  1. Um novo encadeamento Java é solicitado por um aplicativo em execução dentro da JVM
  2. O código nativo da JVM proxies a solicitação para criar um novo encadeamento nativo para o SO O SO tenta criar um novo encadeamento nativo que requer que a memória seja alocada para o encadeamento
  3. O sistema operacional recusará a alocação de memória nativa porque o tamanho do processo Java de 32 bits esgotou seu espaço de endereço de memória - por exemplo, foi atingido o limite de tamanho do processo (2-4) GB - ou a memória virtual do sistema operacional foi totalmente esgotada
  4. O java.lang.OutOfMemoryError: Não foi possível criar um novo erro de encadeamento nativo.

Referência: https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread

Sazzad Hissain Khan
fonte
2

Para descobrir quais processos estão criando threads, tente:

ps huH

Eu normalmente redireciono a saída para um arquivo e analiso o arquivo offline (a contagem de threads para cada processo é conforme o esperado ou não)

user8521771
fonte
1

Se sua tarefa estiver falhando devido ao OutOfMemmory nos nós, você poderá alterar seu número de mapas e redutores máximos e a JVM optar por cada um. mapred.child.java.opts (o padrão é 200Xmx) geralmente precisa ser aumentado com base no hardware específico do seu nó de dados.

Este link pode ser útil ... pls check

Pavan Kumar K
fonte
1
Todos nós já tentamos a mudança que é dada nesse link. Mas o resultado é o mesmo :(
Deepak Tewani
1

sua configuração do JBoss tem alguns problemas, /opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m Xms e Xmx estão limitando o uso de memória do JBoss ao valor configurado, portanto, a partir de 8Gb, o servidor tem apenas 512M + alguns extras para seu próprio objetivo, aumente esse número, lembre-se de deixar alguns gratuitos para o sistema operacional e outras coisas em execução no site e talvez você o faça funcionar, apesar do código desagradável. Corrigir o código também seria bom, se você puder.

user3390284
fonte
1

Este erro pode aparecer devido aos seguintes motivos:

  • Não há espaço na memória para acomodar novos threads.

  • O número de threads excede o limite do sistema operacional.

Duvido que o número de threads tenha excedido o limite para o processo java

Então, provavelmente, o problema é por causa da memória. Um ponto a considerar é

os encadeamentos não são criados no heap da JVM. Eles são criados fora do heap da JVM. Portanto, se houver menos espaço na RAM, após a alocação de heap da JVM, o aplicativo será executado em “java.lang.OutOfMemoryError: incapaz de criar um novo encadeamento nativo”.

A solução possível é reduzir a memória heap ou aumentar o tamanho geral da ram

Maverick
fonte
0

Eu tive esse mesmo problema e acabou sendo um uso inadequado de uma API java. Eu estava inicializando um construtor em um método de processamento em lote que não deveria ser inicializado mais de uma vez.

Basicamente, eu estava fazendo algo como:

for (batch in batches) {
    process_batch(batch)
}

def process_batch(batch) {
    var client = TransportClient.builder().build()
    client.processList(batch)
}

quando eu deveria ter feito isso:

for (batch in batches) {
    var client = TransportClient.builder().build()
    process_batch(batch, client)
}

def process_batch(batch, client) {
    client.processList(batch)
}
anthonybell
fonte
-4

Antes de tudo, eu não culparia tanto o OS / VM ... mas o desenvolvedor que escreveu o código que cria tantos Threads . Basicamente, em algum lugar do seu código (ou de terceiros), muitos threads são criados sem controle .

Revise cuidadosamente o código de rastreamento de pilha e controle o número de threads que são criados. Normalmente, seu aplicativo não deve precisar de uma grande quantidade de threads, se houver, é um problema diferente.

Flueras Bogdan
fonte
10
Esta não é uma solução para a pergunta.
ftrujillo