Pourquoi ce petit programme Java fait-il redémarrer macOS?


Le code est le suivant

Set<Thread> threads = new HashSet<>();

Runnable r = () -> {
    try {
        Thread.sleep(Long.MAX_VALUE);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
};

for (int i = 0; i < 20000; i++) {
    Thread t = new Thread(r);
    threads.add(t);
    t.start();
    if (i % 100 == 0) {
        System.out.println(i);
    }
    Thread.sleep(2);
}

Lors de l'exécution, je commence à voir des valeurs comme

0
100
200
300

Comme prévu, et il va jusqu'à ce que je vois:

3900
4000
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:717)
    at App.main(scratch.java:24)
Java HotSpot(TM) 64-Bit Server VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGINT to handler- the VM may need to be forcibly terminated

Mais après un court moment (10 à 20 secondes environ), macOS décide de redémarrer. Quelle est la cause du redémarrage que je vois ici? Le thread principal lance une exception, mais le processus ayant ~4000 threads en sommeil provoque ... ce qui, dans le système d'exploitation? Est-ce un débordement de mémoire ou lié au planificateur de tâches du OS?

MacOS version: 10.14.3 (18D109)
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)
Author: Koray Tugay, 2019-02-16

5 answers

Malgré le fait que la console indique que le programme est terminé, le processus JVM s'exécute toujours jusqu'à ce que toutes les ressources soient libérées. Pendant ce temps, votre système d'exploitation est à court de threads, lent et instable, ce qui entraîne un retard dans tous les processus, y compris la finalisation de la JVM. En tant que légitime défense, le système d'exploitation déclenche une panique du noyau. Et c'est pourquoi votre macOS redémarre.

* OS-Système d'exploitation

 9
Author: Badaro, 2019-02-25 17:08:53

Java a été construit dans les années 90, quand il n'y avait que des processeurs multicœurs.

Java a sûrement évolué, tout comme les processeurs modernes. De nos jours, nous avons des processeurs 8 cœurs, avec de grandes caches (par exemple: 12 Mo).

Même si le traitement simultané a beaucoup évolué, Java est toujours conçu autour du modèle de processeur 1 cœur. Mais, assez avec l'histoire, permettez-moi d'expliquer très très simplement ce qui se passe.

Juste en créant simplement un nouveau thread en Java, nous gaspillons beaucoup de mémoire.

Chaque thread consomme environ ~ 512 Ko - 1 Mo, en fonction de votre version JVM (voir combien de mémoire un thread prend en javaet Java Thread: Mémoire conservée). En gardant cela à l'esprit, lors de la création continue de nouveaux Threads, à un moment donné, ils consommeront toute la mémoire du tas.

Maintenant, je n'ai jamais essayé cela par moi-même, mais je suppose que le système d'exploitation de votre ordinateur s'arrête/redémarre en raison de l'erreur "out of memory", comme un contre-mesure. (C'est un peu comme le triple défaut , qui a causé le tristement célèbre"Écran bleu de la mort" sur Windows, où la machine devait redémarrer pour réinitialiser l'état du PROCESSEUR)

Une solution possible pour cela, est de définir manuellement la taille maximale du tas à utiliser par la JVM. Ainsi, lorsque votre programme utilise complètement le tas pré-alloué, il ne provoquera pas d'arrêt. Veuillez vous référer à cette DONC question sur la façon de le faire.

 3
Author: Soutzikevich, 2019-02-25 21:06:43

Je suis juste tombé sur le même problème aujourd'hui. Voici du code python déclenchant la même panique du noyau sur 10.15.5 (Catalina). Testé sur deux mac pour vous assurer que ce n'est pas un problème matériel:

Https://github.com/ephes/django_async/blob/master/measure_threads_memory.py

Peut-être que je vais écrire un rapport de bogue.

 1
Author: ephes, 2020-07-07 14:53:21

Il est un Fourche bombe variante. Cela peut provoquer un ralentissement sévère, mais aucun programme utilisateur ne devrait pouvoir planter le système d'exploitation. C'est probablement un bogue dans le système d'exploitation ou une erreur de mémoire. Essayez d'exécuter une vérification de mémoire?

 0
Author: ErikWi, 2019-02-24 05:42:19

Très probablement parce que vous n'avez pas donné suffisamment de mémoire à votre JVM, ou que votre matériel informatique et la combinaison macOS ne permettent pas à autant de threads d'être actifs à la fois. Ce problème n'est pas limité à macOS, mais certaines distributions Linux, par exemple Bodhi Linux, ont également cette limitation. Ne vous laissez pas tromper par "OutOfMemoryError" - cela peut souvent signifier que la JVM n'a pas pu allouer un thread natif.

 -4
Author: Sina Madani, 2019-02-16 17:16:45