"Java.lang.OutOfMemoryError: impossible de créer un nouveau thread natif"


124

Nous obtenons "java.lang.OutOfMemoryError : unable to create new native Thread"sur 8 Go de RAM VM après 32k threads (ps -eLF | grep -c java)

Cependant, "top" and "free -m" shows 50% free memory available. JDk est 64 bits et essayé avec HotSpot et JRockit.Server a Linux 2.6.18

Nous avons également essayé de OS stack size (ulimit -s)peaufiner les limites du processus max (ulimit -u), augmenter limit.conf mais en vain.

Nous avons également essayé presque toutes les combinaisons de tailles de tas possibles, en les gardant bas, haut, etc.

Le script que nous utilisons pour exécuter l'application est

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

Merci pour la réponse.

Nous avons essayé d'éditer /etc/security/limits.conf et ulimit mais toujours pareil

[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
Les systèmes d'exploitation ont des limites sur le nombre de threads que vous pouvez créer. Pourquoi créez-vous plus de 32 000 threads? Votre système n'a probablement pas des milliers de cœurs de processeur, créer autant de threads n'est pas utile. Utilisez ExecutorServiceplutôt un pool de threads ( ).
Jesper

Merci pour la réponse. Nous utilisons une bibliothèque open source et essayons de charger le test. Toute bibliothèque open source crée autant de threads. Mais ce que je ne comprends pas, c'est quand "top" montre 50% de mémoire libre, alors pourquoi OutOfMemory Error.
Deepak Tewani

La bibliothèque open source que nous utilisons dans la bibliothèque ICE4j
Deepak Tewani

11
OutOfMemoryError ne signifie pas nécessairement que l'espace du tas, ou la RAM "générale", a été épuisé. Dans ce cas, il est clair que l'échec était dû au fait que le système d'exploitation n'avait pas les ressources pour allouer un thread supplémentaire. Avoir 50% de mémoire libre n'est pas pertinent pour cet échec particulier.
Andrzej Doyle

1
Quelles sont les autres ressources requises pour créer de nouveaux threads. Nous avions l'impression que si nous augmentons la RAM, nous pourrions créer plus de threads. Veuillez nous guider
Deepak Tewani

Réponses:


80

Ce n'est pas un problème de mémoire même si le nom de l'exception le suggère fortement, mais un problème de ressources du système d'exploitation. Vous manquez de threads natifs, c'est-à-dire combien de threads le système d'exploitation autorisera votre JVM à utiliser.

C'est un problème rare, car vous en avez rarement besoin. Avez-vous beaucoup de threads inconditionnels qui apparaissent là où les threads devraient mais ne se terminent pas?

Vous pourriez envisager de réécrire en utilisant Callable / Runnables sous le contrôle d'un exécuteur si possible. Il existe de nombreux exécuteurs standard avec différents comportements que votre code peut facilement contrôler.

(Il existe de nombreuses raisons pour lesquelles le nombre de threads est limité, mais elles varient d'un système d'exploitation à l'autre)


Merci pour la réponse. Nous utilisons une bibliothèque open source ICE4j et essayons de charger le test. On ne peut pas augmenter la limite de threads dans l'OS quand on sait qu'il reste 50% de mémoire sur le serveur.
Deepak Tewani

Peut-être, mais je pense que cela ne vous aidera pas en tant que tel. Si vous manquez de ressources lors des tests de charge, vous devez être en mesure de contrôler ce qui se passe dans votre application. Pourquoi avez-vous 32000 threads actifs à la fois?
Thorbjørn Ravn Andersen

Nous créons des clients 11K qui utilisent 32 K threads pour lire et écrire des données sur des sockets UDP. Sur ces threads de 32 K, les threads 10K sont des threads de maintien en vie qui sont utilisés pour maintenir le socket ouvert
Deepak Tewani

Je crois que ce problème est résolu dans les serveurs Web modernes. UDP peut également perdre des paquets - une raison pour laquelle vous n'utilisez pas simplement un serveur Web?
Thorbjørn Ravn Andersen

7
Parce que l'exception OutOfMemory doit avoir été nommée OutOfResources. Le système d'exploitation ne peut pas fournir la ressource dont vous avez besoin. (Et il s'est avéré que je ne connaissais pas ice4j)
Thorbjørn Ravn Andersen

14

J'ai rencontré le même problème lors du test de charge, la raison en est que JVM est incapable de créer un nouveau thread Java. Ci-dessous le code source 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);`

Cause fondamentale: JVM lève cette exception lorsque JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR (ressources épuisées (signifie mémoire épuisée)) ou JVMTI_RESOURCE_EXHAUSTED_THREADS (Threads épuisés).

Dans mon cas, Jboss crée trop de threads pour répondre à la demande, mais tous les threads sont bloqués. Pour cette raison, JVM est épuisé avec des threads ainsi qu'avec de la mémoire (chaque thread contient de la mémoire, qui n'est pas libérée, car chaque thread est bloqué).

Analyse des vidages de thread java observés que près de 61K threads sont bloqués par l'une de nos méthodes, ce qui cause ce problème. Ci-dessous, la partie de la décharge de thread

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

Comment la méthode s'est-elle bloquée? Vous ne revenez jamais?
Thorbjørn Ravn Andersen

8

Il est probable que votre système d'exploitation n'autorise pas le nombre de threads que vous essayez de créer ou que vous atteignez une limite dans la JVM. Surtout s'il s'agit d'un nombre aussi rond que 32k, une limite d'un type ou d'un autre est un coupable très probable.

Êtes-vous sûr d'avoir vraiment besoin de threads 32k? La plupart des langages modernes ont une sorte de support pour les pools de threads réutilisables - je suis sûr que Java a également quelque chose en place (comme ExecutorService, comme l'utilisateur Jesper l'a mentionné). Vous pourriez peut-être demander des threads à un tel pool, au lieu d'en créer manuellement de nouveaux.


1
Merci pour la réponse Nous utilisons une bibliothèque open source ICE4j et essayons de charger le test. On ne peut pas augmenter la limite de threads dans l'OS quand on sait qu'il reste 50% de mémoire sur le serveur.
Deepak Tewani

1
Nous créons des clients 11K qui utilisent 32 K threads pour lire et écrire des données sur des sockets UDP. Sur ces 32 K threads, 10K threads sont des threads de maintien en vie qui sont utilisés pour garder le socket ouvert
Deepak Tewani

7

Je recommanderais également de regarder la taille de la pile de threads et de voir si vous obtenez plus de threads créés. La taille de la pile de threads par défaut pour JRockit 1.5 / 1.6 est de 1 Mo pour une machine virtuelle 64 bits sur un système d'exploitation Linux. Les threads 32K nécessiteront une quantité importante de mémoire physique et virtuelle pour respecter cette exigence.

Essayez de réduire la taille de la pile à 512 Ko comme point de départ et voyez si cela aide à créer plus de threads pour votre application. Je recommande également d'explorer la mise à l'échelle horizontale, par exemple en divisant le traitement de votre application sur plusieurs machines physiques ou virtuelles.

Lors de l'utilisation d'une machine virtuelle 64 bits, la vraie limite dépendra de la disponibilité de la mémoire physique et virtuelle du système d'exploitation et des paramètres de réglage du système d'exploitation tels que ulimitc. Je recommande également l'article suivant comme référence:

OutOfMemoryError: impossible de créer un nouveau thread natif - Problème démystifié


5

Si jvm est démarré via systemd, il peut y avoir une limite maxTasks par processus (les tâches signifient en fait des threads) dans certains OS Linux.

Vous pouvez vérifier cela en exécutant "état du service" et vérifier s'il existe une limite maxTasks. Si c'est le cas, vous pouvez le supprimer en éditant /etc/systemd/system.conf, en ajoutant une configuration: DefaultTasksMax = infinity


3

J'ai eu le même problème en raison de processus fantômes qui n'apparaissaient pas lors de l'utilisation de top dans bash. Cela a empêché la JVM de générer plus de threads.

Pour moi, cela s'est résolu lors de la liste de tous les processus java avec jps (exécutez simplement jpsdans votre shell) et les a tués séparément en utilisant lekill -9 pid commande bash pour chaque processus fantôme.

Cela peut aider dans certains scénarios.


2

Vous avez une chance de faire face à java.lang.OutOfMemoryError: Unable to create new native threadchaque fois que la JVM demande un nouveau thread à partir du système d'exploitation. Chaque fois que le système d'exploitation sous-jacent ne peut pas allouer un nouveau thread natif, cette OutOfMemoryError sera levée. La limite exacte pour les threads natifs est très dépendante de la plate-forme, il est donc recommandé de connaître ces limites en exécutant un test similaire à l'exemple de lien ci-dessous. Mais, en général, la situation à l'origine java.lang.OutOfMemoryError: Unable to create new native threadpasse par les phases suivantes:

  1. Un nouveau thread Java est demandé par une application s'exécutant dans la JVM
  2. Le code natif de la JVM envoie par proxy la demande de création d'un nouveau thread natif au système d'exploitation Le système d'exploitation tente de créer un nouveau thread natif qui nécessite que de la mémoire soit allouée au thread
  3. Le système d'exploitation refusera l'allocation de mémoire native soit parce que la taille du processus Java 32 bits a épuisé son espace d'adressage mémoire - par exemple, la limite de taille de processus de 2 à 4 Go a été atteinte - soit la mémoire virtuelle du système d'exploitation a été complètement épuisée
  4. L'erreur java.lang.OutOfMemoryError: Impossible de créer une nouvelle erreur de thread natif est renvoyée.

Référence: https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread


2

Pour trouver quels processus créent des threads, essayez:

ps huH

Je redirige normalement la sortie vers un fichier et analyse le fichier hors ligne (le nombre de threads pour chaque processus est-il conforme ou non)


1

Si votre Job échoue à cause d'OutOfMemmory sur les nœuds, vous pouvez tweek votre nombre maximum de cartes et de réducteurs et la JVM opte pour chacun. mapred.child.java.opts (la valeur par défaut est 200Xmx) doit généralement être augmenté en fonction du matériel spécifique de vos nœuds de données.

Ce lien pourrait être utile ... veuillez vérifier


1
Nous avons tous déjà essayé ce changement qui est donné sur ce lien. Mais le résultat est le même :(
Deepak Tewani

1

votre configuration JBoss a quelques problèmes, /opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m Xms et Xmx limitent votre utilisation de la mémoire JBoss, à la valeur configurée, donc à partir du 8 Go, le serveur utilise seulement 512 Mo + un supplément pour son propre but, augmentez ce nombre, n'oubliez pas de laisser un peu de libre pour le système d'exploitation et d'autres choses qui y fonctionnent et peut-être le faire fonctionner malgré un code peu recommandable. Corriger le code serait bien aussi, si vous le pouvez.


1

Cette erreur peut apparaître pour les deux raisons suivantes:

  • Il n'y a pas de place dans la mémoire pour accueillir de nouveaux threads.

  • Le nombre de threads dépasse la limite du système d'exploitation.

Je doute que le nombre de threads ait dépassé la limite du processus java

Il est donc possible que le problème soit dû à la mémoire Un point à considérer est

les threads ne sont pas créés dans le tas JVM. Ils sont créés en dehors du tas JVM. Donc, s'il reste moins de place dans la RAM, après l'allocation du tas JVM, l'application fonctionnera dans «java.lang.OutOfMemoryError: impossible de créer un nouveau thread natif».

La solution possible consiste à réduire la mémoire du tas ou à augmenter la taille globale de la RAM


0

J'ai eu ce même problème et il s'est avéré être une mauvaise utilisation d'une API Java. J'initialisais un constructeur dans une méthode de traitement par lots qui n'était pas censée être initiée plus d'une fois.

En gros, je faisais quelque chose comme:

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

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

quand j'aurais dû faire ça:

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

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

-4

Tout d'abord, je ne blâmerais pas autant le système d'exploitation / machine virtuelle ... plutôt le développeur qui a écrit le code qui crée tellement de threads . Fondamentalement, quelque part dans votre code (ou tiers), de nombreux threads sont créés sans contrôle .

Examinez attentivement les stacktraces / code et contrôlez le nombre de threads créés. Normalement, votre application ne devrait pas avoir besoin d'une grande quantité de threads, si c'est le cas, c'est un problème différent.


10
Ce n'est pas une solution à la question.
ftrujillo
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.