Erreur Java: java.lang.IllegalArgumentException: Signal déjà utilisé par la machine virtuelle: INT

StackOverflow https://stackoverflow.com/questions/1050370

  •  20-08-2019
  •  | 
  •  

Question

J'enquête sur un problème Java (à l'aide d'IBM JVM 1.4.2 64 bits) sous Red Hat Linux. Je me demande si quelqu'un a déjà vu ce message d'erreur et sait s'il existe une solution de contournement à ce problème?

Source:

import sun.misc.Signal;
import sun.misc.SignalHandler;

public class SignalTest extends Thread
{
    private static Signal signal = new Signal("INT");

    private static ShutdownHandler handler = new ShutdownHandler();

    private static class ShutdownHandler implements SignalHandler
    {
        public void handle(Signal sig)
        {
        }
    }

    public static void main(String[] args)
    {
        try
        {
            Signal.handle(signal, handler);
        }
        catch(Throwable e)
        {
            e.printStackTrace();
        }

        try { Thread.sleep(5000); } catch(Exception e) { e.printStackTrace(); }

        System.exit(0);
    }
}

Sortie:

java.lang.IllegalArgumentException <Signal already used by VM: INT>
java.lang.IllegalArgumentException: Signal already used by VM: INT
at
com.ibm.misc.SignalDispatcher.registerSignal(SignalDispatcher.java:145)
at sun.misc.Signal.handle(Signal.java:199)
at xxx

Informations complémentaires:

J'ai découvert quelque chose d'étrange. La raison de son échec est que j'exécute le programme dans un script shell en tant que processus d'arrière-plan.

i.e. sigtest.sh:

#!/bin/bash
java -cp . SignalTest >> sigtest.log 2>&1 &

Si j'exécute le programme à partir de la ligne de commande, ou si je supprime & "; & amp; &"; (c'est-à-dire d'en faire un processus de premier plan dans le script shell), cela ne pose pas de problème ... Je ne comprends pas pourquoi c'est le cas.

Était-ce utile?

La solution

C’est peut-être un problème spécifique à la mise en oeuvre de la machine virtuelle Java. Nous utilisons une API non documentée / non prise en charge (sun.misc.Signal/SignalHandler) et par conséquent, aucun contrat sur le comportement de l'API n'est garanti.

L’implémentation JVM d’IBM peut effectuer les opérations de traitement du signal différemment de l’implémentation JVM SUN et donc causer ce problème. Pour que ce cas d'utilisation spécifique fonctionne dans la JVM SUN mais pas dans la JVM IBM.

Mais essayez ce qui suit (je ne peux pas l'essayer moi-même):

Faites toutes les combinaisons de démarrage de la machine virtuelle Java avec un / deux / trois de ces paramètres et leurs combinaisons de valeurs possibles.

  1. l'option -Xrs spécifiée / non spécifiée
  2. la propriété ibm.signalhandling.sigint définie sur true / false
  3. la propriété ibm.signalhandling.rs définie sur SIGINT / <=>

(Les propriétés ont été trouvées via Google dans plusieurs vidages d’erreur mais je ne trouve aucune documentation spécifique dessus.

Je ne sais pas si la machine virtuelle Java IBM prend également en charge cet indicateur spécial, mais vous pouvez également essayer de l'ajouter, ce qui dans la machine virtuelle Java SUN semble être spécifique à certains problèmes liés aux gestionnaires de signaux sous linux / solaris

-XX:-AllowUserSignalHandlers

Ou essayez d’utiliser un gestionnaire de signal natif si cette option vous convient. Découvrez les exemples de code fournis:

Bien qu'il ne soit pas lié à votre problème spécifique, un article IBM sur la gestion du signal JVM (légèrement daté mais toujours correct). Avec des exemples pour les gestionnaires de signaux de code natif:

Révélations sur la gestion et la résiliation du signal Java

Mais je suppose que tout cela n’aura peut-être aucune utilité, car l’implémentation de la machine virtuelle Java IBM pourrait compter sur le traitement de <=> lui-même pour fonctionner correctement et ne vous donne donc jamais la chance de le gérer vous-même.

Btw. à partir de la description de <<> l'indicateur Je comprends que cela puisse vous empêcher de faire ce que vous voulez. Il dit

  

Lorsque <=> est utilisé sur la machine virtuelle Java de Sun, le   masques de signaux pour SIGINT, SIGTERM,   SIGHUP et SIGQUIT ne sont pas modifiés par   la machine virtuelle Java et les gestionnaires de signaux pour ces    Les signaux ne sont pas installés .

Ou cela pourrait signifier que seules les actions par défaut de la JVM pour les signaux ne sont pas exécutées. Cela pourrait également dépendre de l’implémentation de la machine virtuelle Java.

Autres conseils

Essayez de démarrer la machine virtuelle Java avec une option -Xrs valide sur la machine virtuelle IBM conformément à ceci de toute façon. Cela pourrait empêcher le conflit.

EDIT: en réponse à votre désir sous-jacent, regardez:

Runtime.getRuntime (). AddShutdownHook (Fil de discussion)

Vous sous-classez un objet thread et celui-ci démarrera dans le cadre de l'arrêt (supprimez -Xrs pour que cela fonctionne correctement). Certaines choses (par exemple, appeler stop sur Runtime) peuvent empêcher cela de se produire. Vous devez donc être conscient de la possibilité que cela ne se produise tout simplement pas.

Comme Heinz Kabutz , les signaux que vous êtes en mesure de capter dépendent le système d'exploitation que vous utilisez et probablement la version de la JVM. Si une certaine combinaison os / jvm ne vous permet pas d'enregistrer votre signal, vous n'avez pas de chance. Peut-être que peaufiner avec les paramètres os / vm pourrait aider.

Selon votre commentaire, l'ajout d'un crochet de fermeture proposé par Yishai devrait le truc.

L'exception se produit car la VM a déjà un gestionnaire de signal mis en place pour SIGINT. Ce que vous pouvez / devez faire à ce sujet dépend du contexte dans lequel cette exception est levée.

J'ai essayé le même code et cela fonctionne pour moi. Donc, je suppose qu'il pourrait y avoir une différence dans la configuration.

Après avoir ajouté

System.out.println("Hello");

au message descripteur, je peux exécuter la classe de la manière suivante:

z@zolty:/tmp/so$ java SignalTest & sleep 1s && kill -2 $!
[1] 20467
z@zolty:/tmp/so$ Hello
z@zolty:/tmp/so$
z@zolty:/tmp/so$ java SignalTest
[1]+  Done             java SignalTest

Cela a fonctionné en utilisant une implémentation JVM différente (SuSE) au lieu d’IBM. Lorsqu’il s’agit de fonctionnalités non documentées, il apparaît que les machines JVM n’ont pas un comportement très cohérent.

Moi aussi j'ai le même problème. Je lance le programme Java à partir d'un script ksh. Si je lance le script avec le compte qui a le profil csh c'est-à-dire dans le fichier / etc / passwd

userx: *: 7260: 20 :: / home / userx: / usr / bin / csh

Le script sera exécuté avec succès. Mais si je le lance avec un compte qui a un profil autre que sh, cela donne la même erreur.

La solution consiste donc à modifier votre profil utilisateur Unix en csh.

J'ai également rencontré ce problème avec la machine virtuelle Java IBM (64 bits) sous Linux. Il s’est avéré que la machine virtuelle Java est sensible au masque de signalisation du processus qui l’appelle.

> grep Sig /proc/self/status
SigQ:   1/1030663
SigPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000001001006
SigCgt: 0000000000000000

Notez que le bit pour SIGINT (valeur 2) est défini dans SigIgn. Lors du démarrage de la machine virtuelle IBM avec ce masque, celle-ci refuse d'installer un gestionnaire pour SIGINT. J'ai résolu le problème en lançant la machine virtuelle via un wrapper Python qui réinitialise le gestionnaire SIGINT à la valeur par défaut:

#!/usr/bin/env python

import os
import signal
import sys

signal.signal(signal.SIGINT, signal.SIG_DFL)

args = sys.argv[1:]
os.execv(args[0], args)

Le premier argument du wrapper est la commande java, puis suivez les arguments de la machine virtuelle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top