28 votes

Erreur de mémoire Java : impossible de créer un nouveau thread natif

J'obtiens cette erreur sur mon serveur UNIX, lorsque je lance mon serveur java :

Exception in thread "Thread-0" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:640)
at [... where ever I launch a new Thread ...]

Cela se produit chaque fois que j'ai environ 600 fils en cours d'exécution.

J'ai configuré cette variable sur le serveur :

$> ulimit -s 128

Ce qui me semble étrange, c'est le résultat de cette commande, que j'ai exécutée lorsque le bogue s'est produit la dernière fois :

$> free -m
              total       used       free     shared    buffers     cached
Mem:          2048        338       1709          0          0          0
-/+ buffers/cache:        338       1709
Swap:            0          0          0

Je lance mon serveur java comme ceci :

$> /usr/bin/java -server -Xss128k -Xmx500m -jar /path/to/myJar.jar

Ma version debian :

$> cat /etc/debian_version
5.0.8

Ma version de java :

$> java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)

Ma question : J'ai lu sur Internet que mon programme devrait gérer quelque chose comme 5000 threads ou plus. Que se passe-t-il donc, et comment y remédier ?


Edit : voici le résultat de ulimit -a quand j'ouvre un shell :

core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 794624
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 100000
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) 794624
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

J'exécute le script comme un démon depuis init.d, et voici ce que j'exécute :

DAEMON=/usr/bin/java
DAEMON_ARGS="-server -Xss128k -Xmx1024m -jar /path/to/myJar.jar"
ulimit -s 128 && ulimit -n 10240 && start-stop-daemon -b --start --quiet --chuid $USER -m -p $PIDFILE --exec $DAEMON -- $DAEMON_ARGS \
    || return 2

Edit2 : Je suis tombé sur cette question de stack overflow avec un test java pour les threads : how-many-threads-can-a-java-vm-support

    public class DieLikeADog { 
        private static Object s = new Object(); 
        private static int count = 0; 
        public static void main(String[] argv){ 
            for(;;){ 
                new Thread(new Runnable(){ 
                        public void run(){ 
                            synchronized(s){ 
                                count += 1; 
                                System.err.println("New thread #"+count); 
                            } 
                            for(;;){ 
                                try { 
                                    Thread.sleep(100); 
                                } catch (Exception e){ 
                                    System.err.println(e); 
                                } 
                            } 
                        } 
                    }).start(); 
            } 
        } 
    } 

Sur mon serveur, le programme se bloque après 613 threads. Je suis maintenant certain que ce n'est pas normal et que c'est uniquement lié à la configuration de mon serveur. Quelqu'un peut-il m'aider ?


Edit 3 : Je suis tombé sur cet article, et beaucoup d'autres, expliquant que linux ne peut pas créer 1000 threads mais vous me dites que vous pouvez le faire sur vos systèmes. Je ne comprends pas.

J'ai également exécuté ce script sur mon serveur : threads_limits.c et la limite est d'environ 620 fils.

Mon site web est maintenant hors ligne et c'est la pire chose qui aurait pu arriver à mon projet. Je ne sais pas comment recompiler la glibc et tout ça. C'est trop de travail, je pense.

Je suppose que je devrais passer au serveur Windows. Car aucun des paramètres proposés sur cette page n'a apporté de changement : La limite sur mon système se situe entre 600 et 620 threads, quel que soit le programme concerné.

15voto

Joel Points 1734

Je viens de recevoir l'information suivante : Il s'agit d'une limitation imposée par mon hébergeur. Cela n'a rien à voir avec la programmation, ou linux.

7voto

esaj Points 8338

Le système d'exploitation sous-jacent (Debian Linux dans ce cas) ne permet pas au processus de créer d'autres threads. Voir ici comment augmenter la quantité maximale : Nombre maximum de threads par processus sous Linux ?

J'ai lu sur Internet que mon prog 5000 threads ou plus.

Cela dépend des limites fixées au système d'exploitation, du nombre de processus en cours, etc. Avec des paramètres corrects, vous pouvez facilement atteindre ce nombre de threads. J'utilise Ubuntu sur mon propre ordinateur, et je peux créer environ 32000 threads avant d'atteindre la limite sur un seul programme Java avec tous mes "trucs normaux" en arrière-plan (ceci a été fait avec un programme de test qui créait juste des threads qui s'endormaient immédiatement dans une boucle infinie). Naturellement, un nombre aussi élevé de threads faisant réellement quelque chose aurait probablement pour effet de faire s'arrêter le matériel grand public assez rapidement.

3voto

Kevin Points 2483

Pouvez-vous essayer la même commande avec une taille de pile plus petite "-Xss64k" et transmettre les résultats ?

2voto

Adam Zalcman Points 13198

Votre JVM ne parvient pas à allouer de la mémoire de pile ou une autre mémoire pour chaque thread. Réduire la taille de la pile avec -Xss vous aidera à augmenter le nombre de threads que vous pouvez créer avant que l'OOM ne se produise (mais la JVM ne vous laissera pas définir une taille de pile arbitrairement petite).

Vous pouvez confirmer que c'est le problème en voyant comment le nombre de fils créés change lorsque vous modifiez -Xss ou en exécutant strace sur votre JVM (vous verrez presque certainement un bouton mmap() en retournant sur ENOMEM juste avant qu'une exception ne soit levée).

Vérifiez également votre ulimit sur la taille virtuelle, c'est-à-dire ulimit -v . Augmenter cette limite devrait vous permettre de créer plus de threads avec la même taille de pile. Notez que la limite de taille des résidents ( ulimit -m ) est inefficace dans le noyau Linux actuel .

De même, l'abaissement -Xmx peut aider en laissant plus de mémoire pour les piles de threads.

2voto

KarlP Points 3246

Je commence à soupçonner qu'il manque la "Native Posix Thread Library".

>getconf GNU_LIBPTHREAD_VERSION

Cela devrait donner quelque chose comme :

NPTL 2.13

Si ce n'est pas le cas, l'installation de Debian est défectueuse. Je ne sais pas comment réparer cela, mais installer Ubuntu Server semble être une bonne idée...

pour ulimit -n 100000 ; (open fd:s) le programme suivant devrait être capable de gérer environ 32.000 threads.

Essayez-le :

package test;

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.Semaphore;

public class Test {

    final static Semaphore ss = new Semaphore(0);

    static class TT implements Runnable {

        @Override
        public void run() {
            try {
                Socket t = new Socket("localhost", 47111);
                InputStream is = t.getInputStream();
                for (;;) {
                    is.read();
                }

            } catch (Throwable t) {
                System.err.println(Thread.currentThread().getName() + " : abort");
                t.printStackTrace();
                System.exit(2);
            }

        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {

            Thread t = new Thread() {
                public void run() {
                    try {
                        ArrayList<Socket> sockets = new ArrayList<Socket>(50000);
                        ServerSocket s = new ServerSocket(47111,1500);
                        ss.release();

                        for (;;) {
                            Socket t = s.accept();
                            sockets.add(t);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.exit(1);

                    }
                }
            };

            t.start();
            ss.acquire();

            for (int i = 0; i < 30000; i++) {

                Thread tt = new Thread(new TT(), "T" + i);
                tt.setDaemon(true);
                tt.start();
                System.out.println(tt.getName());
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    return;
                }
            }

            for (;;) {
                System.out.println();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    return;
                }
            }

        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X