"Java.lang.OutOfMemoryError: impossibile creare un nuovo thread nativo"


124

Stiamo ottenendo "java.lang.OutOfMemoryError : unable to create new native Thread"su una VM da 8 GB di RAM dopo 32k thread (ps -eLF | grep -c java)

Tuttavia, "top" and "free -m" shows 50% free memory available. JDk è a 64 bit e provato con HotSpot e JRockit.Server ha Linux 2.6.18

Abbiamo anche provato a OS stack size (ulimit -s)modificare i limiti e max process (ulimit -u), limit.conf aumentare ma tutto invano.

Inoltre abbiamo provato quasi tutte le possibili combinazioni di dimensioni dell'heap, mantenendole basse, alte, ecc.

Lo script che usiamo per eseguire l'applicazione è

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

Grazie per la risposta.

Abbiamo provato a modificare /etc/security/limits.conf e ulimit, ma sempre lo stesso

[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

11
I sistemi operativi hanno limiti al numero di thread che è possibile creare. Perché stai creando più di 32k thread? Il tuo sistema molto probabilmente non ha migliaia di core del processore, la creazione di così tanti thread non è utile. Utilizza invece un pool di thread ( ExecutorService).
Jesper

Grazie per la risposta. Stiamo usando una libreria open source e proviamo a caricarla per testarla. Qualsiasi libreria open source sta creando così tanti thread. Ma quello che non capisco, è quando "top" mostra il 50% di memoria libera, allora perché OutOfMemory Error.
Deepak Tewani

La libreria open source che stiamo utilizzando nella ICE4j Library
Deepak Tewani

11
OutOfMemoryError lo fa non necessariamente lo spazio di heap media, o RAM "generale", è stato esaurito. In questo caso è chiaro che l'errore era dovuto al fatto che il sistema operativo non disponeva delle risorse per allocare un thread aggiuntivo. Avere il 50% di memoria libera è irrilevante per questo particolare errore.
Andrzej Doyle

1
Quali sono le altre risorse necessarie per creare nuovi thread. Avevamo l'impressione che se aumentassimo la RAM, potremmo essere in grado di creare più thread. Gentilmente guidaci
Deepak Tewani

Risposte:


80

Questo non è un problema di memoria anche se il nome dell'eccezione lo suggerisce fortemente, ma un problema di risorse del sistema operativo. Stai esaurendo i thread nativi, ovvero quanti thread il sistema operativo consentirà alla tua JVM di utilizzare.

Questo è un problema raro, perché raramente ne hai bisogno di così tanti. Hai molti thread incondizionati che si generano dove i thread dovrebbero ma non finiscono?

Potresti considerare di riscrivere usando Callable / Runnables sotto il controllo di un Executor, se possibile. Ci sono molti esecutori standard con vari comportamenti che il tuo codice può facilmente controllare.

(Ci sono molte ragioni per cui il numero di thread è limitato, ma variano da sistema operativo a sistema operativo)


Grazie per la risposta. Stiamo usando una libreria open source ICE4j e proviamo a caricarla per testarla. Non possiamo aumentare il limite di thread nel sistema operativo quando sappiamo che è rimasto il 50% di memoria sul server.
Deepak Tewani

Forse, ma penso che non ti aiuterà in quanto tale. Se si esauriscono le risorse durante il test di carico, è necessario essere in grado di controllare cosa accade nella propria applicazione. Perché hai 32000 thread attivi contemporaneamente?
Thorbjørn Ravn Andersen

Stiamo creando 11.000 client che utilizzano 32.000 thread per leggere e scrivere dati su socket UDP. Di questi 32.000 thread, 10.000 thread sono thread
attivi

Credo che questo problema sia risolto nei moderni server web. Anche udp può perdere pacchetti: c'è qualche motivo per cui non usi solo un server web?
Thorbjørn Ravn Andersen

7
Perché l'eccezione OutOfMemory avrebbe dovuto essere denominata OutOfResources. Il sistema operativo non è in grado di fornire la risorsa necessaria. (E si è scoperto che non conoscevo ice4j)
Thorbjørn Ravn Andersen

14

Ho riscontrato lo stesso problema durante il test di carico, il motivo è che JVM non è in grado di creare ulteriormente un nuovo thread Java. Di seguito è riportato il codice sorgente 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 principale: JVM genera questa eccezione quando JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR (risorse esaurite (significa memoria esaurita)) o JVMTI_RESOURCE_EXHAUSTED_THREADS (thread esauriti).

Nel mio caso Jboss sta creando troppi thread, per servire la richiesta, ma tutti i thread sono bloccati. Per questo motivo, JVM è esaurita con i thread e anche con la memoria (ogni thread contiene memoria, che non viene rilasciata, perché ogni thread è bloccato).

Analizzati i dump dei thread java, sono stati osservati quasi 61K thread bloccati da uno dei nostri metodi, che causa questo problema. Di seguito è riportata la parte di Thread dump

"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)

Come è stato il blocco del metodo? Mai tornare?
Thorbjørn Ravn Andersen

8

È probabile che il tuo sistema operativo non consenta il numero di thread che stai tentando di creare o che stai raggiungendo un limite nella JVM. Soprattutto se è un numero tondo come 32k, un limite di un tipo o dell'altro è molto probabilmente un colpevole.

Sei sicuro di aver davvero bisogno di 32k thread? La maggior parte dei linguaggi moderni ha una sorta di supporto per pool di thread riutilizzabili: sono sicuro che anche Java ha qualcosa in atto (come ExecutorService, come ha menzionato l'utente Jesper). Forse potresti richiedere thread da un pool di questo tipo, invece di crearne di nuovi manualmente.


1
Grazie per la risposta. Stiamo utilizzando una libreria open source ICE4j e stiamo cercando di caricarla per testarla. Non possiamo aumentare il limite di thread nel sistema operativo quando sappiamo che è rimasto il 50% di memoria sul server.
Deepak Tewani

1
Stiamo creando 11.000 client che utilizzano 32.000 thread per leggere e scrivere dati su socket UDP. Di questi 32.000 thread, 10.000 thread sono thread
attivi

7

Consiglierei di guardare anche le dimensioni dello stack di thread e vedere se vengono creati più thread. La dimensione dello stack di thread predefinita per JRockit 1.5 / 1.6 è 1 MB per VM a 64 bit su sistema operativo Linux. I thread da 32 KB richiederanno una quantità significativa di memoria fisica e virtuale per soddisfare questo requisito.

Prova a ridurre la dimensione dello stack a 512 KB come punto di partenza e vedi se aiuta a creare più thread per la tua applicazione. Consiglio anche di esplorare il ridimensionamento orizzontale, ad esempio suddividendo l'elaborazione dell'applicazione su più macchine fisiche o virtuali.

Quando si utilizza una VM a 64 bit, il limite effettivo dipenderà dalla disponibilità della memoria fisica e virtuale del sistema operativo e dai parametri di ottimizzazione del sistema operativo come ulimitc. Raccomando anche il seguente articolo come riferimento:

OutOfMemoryError: impossibile creare un nuovo thread nativo - Problema demistificato


5

Se jvm viene avviato tramite systemd, potrebbe esserci un limite maxTasks per processo (le attività in realtà significano thread) in alcuni sistemi operativi Linux.

Puoi verificarlo eseguendo "stato del servizio" e controllare se esiste un limite maxTasks. Se c'è, puoi rimuoverlo modificando /etc/systemd/system.conf, aggiungendo una configurazione: DefaultTasksMax = infinity


3

Ho avuto lo stesso problema a causa di processi fantasma che non si sono presentati quando si utilizzava top in bash. Ciò ha impedito alla JVM di generare più thread.

Per me, si è risolto elencando tutti i processi java con jps (basta eseguirlo jpsnella shell) e li ha uccisi separatamente usando ilkill -9 pid comando bash per ogni processo fantasma.

Questo potrebbe aiutare in alcuni scenari.


2

Hai la possibilità di affrontare java.lang.OutOfMemoryError: Unable to create new native threadogni volta che la JVM richiede un nuovo thread dal sistema operativo. Ogni volta che il sistema operativo sottostante non può allocare un nuovo thread nativo, verrà lanciato questo OutOfMemoryError. Il limite esatto per i thread nativi dipende molto dalla piattaforma, quindi si consiglia di scoprire tali limiti eseguendo un test simile all'esempio di collegamento sottostante. Ma, in generale, la situazione che causa java.lang.OutOfMemoryError: Unable to create new native threadpassa attraverso le seguenti fasi:

  1. Un nuovo thread Java viene richiesto da un'applicazione in esecuzione all'interno della JVM
  2. Il codice nativo JVM invia tramite proxy la richiesta di creare un nuovo thread nativo al sistema operativo Il sistema operativo tenta di creare un nuovo thread nativo che richiede l'allocazione di memoria al thread
  3. Il sistema operativo rifiuterà l'allocazione della memoria nativa perché la dimensione del processo Java a 32 bit ha esaurito il suo spazio di indirizzi di memoria, ad esempio è stato raggiunto il limite della dimensione del processo (2-4) GB, oppure la memoria virtuale del sistema operativo è stata completamente esaurita
  4. Viene generato l'errore java.lang.OutOfMemoryError: Impossibile creare un nuovo thread nativo.

Riferimento: https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread


2

Per scoprire quali processi stanno creando thread, prova:

ps huH

Normalmente reindirizzo l'output a un file e analizzo il file offline (il conteggio dei thread per ogni processo è come previsto o meno)


1

Se il tuo lavoro non riesce a causa di OutOfMemmory sui nodi, puoi modificare il numero massimo di mappe e riduttori e la JVM opta per ciascuno. mapred.child.java.opts (il valore predefinito è 200Xmx) di solito deve essere aumentato in base all'hardware specifico dei nodi di dati.

Questo collegamento potrebbe essere utile ... per favore controlla


1
Abbiamo già provato tutti la modifica che viene fornita su quel link. Ma il risultato è lo stesso :(
Deepak Tewani

1

la configurazione di JBoss presenta alcuni problemi, /opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m Xms e Xmx stanno limitando l'utilizzo della memoria JBoss al valore configurato, quindi da 8 GB il server utilizza solo 512 MB + qualche extra per il suo scopo, aumenta quel numero, ricorda di lasciarne un po 'libero per il sistema operativo e altre cose in esecuzione lì e potresti farlo funzionare nonostante il codice sgradevole. Anche aggiustare il codice sarebbe bello, se puoi.


1

Questo errore può emergere per i seguenti due motivi:

  • Non c'è spazio nella memoria per accogliere nuovi thread.

  • Il numero di thread supera il limite del sistema operativo.

Dubito che il numero di thread abbia superato il limite per il processo Java

Quindi è probabile che il problema sia dovuto alla memoria. Un punto da considerare è

i thread non vengono creati all'interno dell'heap JVM. Vengono creati all'esterno dell'heap JVM. Quindi, se è rimasto meno spazio nella RAM, dopo l'allocazione dell'heap della JVM, l'applicazione verrà eseguita in "java.lang.OutOfMemoryError: impossibile creare un nuovo thread nativo".

La soluzione possibile è ridurre la memoria heap o aumentare la dimensione complessiva della ram


0

Ho avuto lo stesso problema e si è scoperto essere un uso improprio di un'API Java. Stavo inizializzando un builder in un metodo di elaborazione batch che non doveva essere inizializzato più di una volta.

Fondamentalmente stavo facendo qualcosa del tipo:

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

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

quando avrei dovuto farlo:

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

def process_batch(batch, client) {
    client.processList(batch)
}

-4

Prima di tutto non biasimerei più di tanto il sistema operativo / VM .. piuttosto lo sviluppatore che ha scritto il codice che crea così tanti thread . Fondamentalmente da qualche parte nel tuo codice (o di terze parti) molti thread vengono creati senza controllo .

Esamina attentamente gli stacktraces / codice e controlla il numero di thread che vengono creati. Normalmente la tua app non dovrebbe aver bisogno di una grande quantità di thread, se lo fa è un problema diverso.


10
Questa non è una soluzione alla domanda.
ftrujillo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.