Java.lang.OutOfMemoryError: impossible de créer un nouveau thread natif - fs->dans exec clone() et execve() clash?


Je rencontre occasionnellement : -

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:691)

J'ai beaucoup lu à ce sujet, et je ne crois pas que je touche une vraie limite, en termes de mémoire physique, mémoire virtuelle (JVM 64 bits), limite de thread, limite de processus ou descripteurs de fichiers.

En fait, je ne suis même pas sûr que cela soit lié au fait que les processus que je remarque être impactés sont des processus Java.

Je soupçonne que c'est un problème dans le noyau Linux, ou peut-être selon la façon dont il est argumenté, un problème dans la JVM Java, ou pthread_create ().

La machine sur laquelle je vois ceci est un monstre: 64 processeurs, 512 Go de RAM (70 Go gratuits). Son fonctionnement RHES 5.11 (Tikanga) 2.6.18-402.el5 x86_64. Les limites sont définies comme ceci

bash-3.2$ cat /proc/sys/kernel/pid_max
65536
bash-3.2$ cat /proc/sys/kernel/threads-max
8257699

bash-3.2$ /sbin/sysctl fs.file-nr
fs.file-nr = 62220      0       1048576

bash-3.2$ /sbin/sysctl fs.file-max
fs.file-max = 1048576

bash-3.2$ 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) 4128849
max locked memory   (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
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) 4128849
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

De nombreux utilisateurs utilisent cet ordinateur, et jusqu'à présent, seuls deux d'entre eux (moi et un autre) ont signalé le problème. La chose commune à propos de ces utilisateurs est que les processus impactés créeront périodiquement des threads Java pendant un court moment, puis de s'arrêter cela aussi, il y aura d'autres processus périodiquement et régulièrement programmés sous le même id utilisateur. Le processus Java victime lui-même n'exécute aucun autre processus lui-même.

Dans mon cas, le processus Java établit régulièrement des connexions JMX, les utilise, puis les ferme, ce qui implique la création de threads en arrière-plan (ce qui n'est pas sous mon contrôle, donc je ne peux pas le mettre en commun). L'autre activité est un script shell en boucle qui exécute certains processus, puis dort, puis se répète. Nombre de processus, nombre de threads par processus, utilisation de la mémoire, utilisation du descripteur de fichier, etc... ainsi, dans certaines limites.

Dans l'implémentation de fork.c, il existe diverses raisons pour lesquelles EAGAIN peut être retourné, principalement des raisons de ressources ou de sécurité (que j'ai du mal à croire dans ce cas), et aussi une relative à copy_fs et fs->in_exec. in_exec peut apparemment être défini lorsqu'il existe un execve non sécurisé, dans check_unsafe_execve (), en fonction de l'utilisation de la structure partagée fs_struct (qui Je ne comprends pas très bien, voir les commentaires à la fin).

Https://github.com/torvalds/linux/blob/e66eded8309ebf679d3d3c1f5820d1f2ca332c71/kernel/fork.c

En substance, il semble qu'il y ait une condition de concurrence ou un alignement de synchronisation malheureux entre le traitement clone() et le traitement execve() qui peut provoquer le retour de clone() EAGAIN. Pour moi, cela semble faux, car il n'y a pas réellement de limite de ressources atteinte, et ne sont pas "trop de processus" par page de manuel pour clone().

Il y a discussion en ligne pour savoir si ce comportement est nécessaire ou correct. http://lkml.iu.edu/hypermail/linux/kernel/0905.0/02309.html

Si l'argument est que si un programme bien élevé devrait réessayer plus tard s'il reçoit EAGAIN de clone (), eh bien, c'est problématique, car comment un programme peut-il différencier un EAGAIN causé par in_exec (qu'il voudrait réessayer) et une véritable pénurie de ressources (qu'il ne voudrait peut-être pas continuer à réessayer pour un temps très long pour).

J'ai vu l'exception sur Java 7 et Java 8, et je ne pense pas que la version compte, donc en regardant n'importe quelle ancienne version source d'OpenJDK, je ne vois aucune nouvelle tentative (os/linux/vm/os_linux.rpc).

De plus, de strace, je peux voir la JVM émettre le clone(), recevoir l'EAGAIN, puis mourir ...

1454948661.318678 clone(
    child_stack=0x2b6297dc5250,
    flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_
    parent_tidptr=0x2b6297dc59d0,
    tls=0x2b6297dc5940, child_tidptr=0x2b6297dc59d0
    ) = -1 EAGAIN (Resource temporarily unavaiable)

À ce stade, je ne suis pas sûr de regarder la bonne source du noyau Linux pour le noyau utilisé. Aussi, je ne comprends pas ce que la fs_struct est, et comment il pourrait être partagé entre les threads et les processus. Donc, après avoir exploré les limites, j'étudie cette autre possibilité parce que c'est ce qui reste.

Si j'ai raison, que faudrait-il pour causer délibérément le problème. J'ai essayé d'écrire des programmes qui démarrent beaucoup de pthreads et fork et exécutent des processus de courte durée afin d'augmenter les chances que clone() se produise en Java en même temps que execve(). J'ai essayé quelques variantes, mais je ne suis pas sûr d'avoir réussi pour obtenir la bonne combinaison d'événements, ou chanceux. C'est probablement parce que je n'apprécie pas pleinement ce que cela signifie d'obtenir un execve () "dangereux".

Qu'est-Ce que fs_struct, quand pourrait-il être partagé, comment puis-je influencer qui?

Ce que je suggère a-t-il un sens?

Des conseils sur la façon de prouver / réfuter mes soupçons?

Author: Andy Key, 2016-02-12