Error de Java: java.lang.IllegalArgumentException: señal ya utilizada por VM: INT

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

  •  20-08-2019
  •  | 
  •  

Pregunta

Estoy investigando un problema de Java (usando IBM JVM 1.4.2 de 64 bits) en Red Hat Linux. Me pregunto si alguien ha visto este mensaje de error antes y sabe si hay una solución a este problema.

Fuente:

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);
    }
}

Salida:

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

Información adicional:

Descubrí algo extraño. La razón por la que falla es porque estoy ejecutando el programa dentro de un script de shell como un proceso en segundo plano.

es decir sigtest.sh:

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

Si ejecuto el programa desde la línea de comando, o elimino el " & amp; " (es decir, convertirlo en un proceso de primer plano dentro del script de shell), no tiene ningún problema ... No entiendo por qué este es el caso.

¿Fue útil?

Solución

Esto puede muy bien ser un problema específico de implementación de JVM. Estamos utilizando una API no documentada / no compatible (sun.misc.Signal/SignalHandler) y, por lo tanto, no se garantiza ningún contrato sobre el comportamiento de la API.

La implementación de IBM JVM podría hacer cosas relacionadas con el manejo de señales de manera diferente a la implementación de SUN JVM y, por lo tanto, causar este problema. Para que este caso de uso específico funcione en SUN JVM pero no en IBM JVM.

Pero pruebe lo siguiente (no puedo probarlo yo mismo):

Realice todas las combinaciones comenzando la JVM con uno / dos / tres de esos parámetros y sus posibles combinaciones de valores.

  1. la opción -Xrs especificada / no especificada
  2. la propiedad ibm.signalhandling.sigint establecida en true / false
  3. la propiedad ibm.signalhandling.rs establecida en SIGINT / <=>

(Las propiedades se encontraron a través de google en varios volcados de error pero no puedo encontrar ninguna documentación específica sobre ellas)

No sé si IBM JVM también es compatible con este indicador especial, pero podría intentar agregarlo también, que en SUN JVM parece ser específico para algunos problemas con los manejadores de señales en Linux / Solaris

-XX:-AllowUserSignalHandlers

O intente usar un controlador de señal nativo si esa es una opción para usted. Consulte los ejemplos de código proporcionados:

Aunque no se relaciona con su problema específico, un artículo de IBM sobre el manejo de la señal JVM (un poco anticuado pero aún mayormente correcto). Con ejemplos para manejadores de señales de código nativo:

Revelaciones sobre el manejo y la terminación de la señal Java


Pero supongo que todo esto puede ser en vano ya que la implementación de IBM JVM podría depender del manejo de <=> para funcionar correctamente y así nunca darle la oportunidad de manejar <=> usted mismo.

Por cierto. desde la descripción a la <=> bandera Entiendo que en realidad puede obstaculizar que hagas lo que quieras. Dice

  

Cuando se usa <=> en la JVM de Sun, el   máscaras de señal para SIGINT, SIGTERM,   SIGHUP y SIGQUIT no se cambian por   JVM y manejadores de señal para estos   Las señales no están instaladas .

O podría significar que solo las acciones predeterminadas de JVM para las señales no se ejecutan. O podría depender de la implementación de JVM lo que realmente significa.

Otros consejos

Intente iniciar la JVM con una opción -Xrs que sea válida en la JVM de IBM según this de todos modos. Eso podría evitar el conflicto.

EDITAR: en respuesta a su deseo subyacente, mire:

Runtime.getRuntime (). AddShutdownHook (Thread)

Subclasifica un objeto de subproceso y comenzará como parte del cierre (elimine ese -Xrs para que esto funcione bien). Algunas cosas (como detener el tiempo de ejecución) pueden evitar que eso suceda, por lo que debe ser consciente de la posibilidad de que simplemente no termine sucediendo.

Según lo escrito por Heinz Kabutz , las señales que puede capturar dependen de el sistema operativo en el que se está ejecutando y, posiblemente, la versión JVM. Si cierta combinación os / jvm no le permite registrar su señal, entonces no tiene suerte. Tal vez ajustar con la configuración os / vm podría ayudar.

De acuerdo con su comentario, agregar un gancho de cierre según lo propuesto por Yishai debería hacer el truco.

La excepción se produce porque la VM ya tiene un controlador de señal para SIGINT. Lo que puede / debe hacer al respecto depende del contexto en el que se produce esta excepción.

He probado el mismo código y me funciona. Así que supongo que puede haber alguna diferencia en la configuración.

Después de agregar

System.out.println("Hello");

al mensaje de manejo, puedo ejecutar la clase así:

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

Conseguí que esto funcionara utilizando una implementación de JVM diferente (SuSE) en lugar de IBM. Cuando se trata de características no documentadas, parece que las JVM no son muy consistentes en el comportamiento.

Yo también tengo el mismo problema. Ejecuto el programa Java desde un script ksh. Si ejecuto el script con la cuenta que tiene el perfil csh es decir, en el archivo / etc / passwd

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

El script se ejecutará con éxito. Pero si lo ejecuto con una cuenta que tiene un perfil distinto de sh, está dando el mismo error.

Entonces, la solución es cambiar su perfil de usuario de Unix a csh.

También he encontrado este problema con IBM JVM (64 bit) en Linux. Resultó que la JVM es sensible a la máscara de señal del proceso que la llama.

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

Tenga en cuenta que el bit para SIGINT (valor 2) se establece en SigIgn. Al iniciar IBM JVM con esta máscara, se niega a instalar un controlador para SIGINT. Resolví el problema iniciando la JVM a través de un contenedor Python que restablece el controlador SIGINT al valor predeterminado:

#!/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)

El primer argumento para el contenedor es el comando java, luego siga los argumentos para la JVM.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top