Error de Java: java.lang.IllegalArgumentException: señal ya utilizada por VM: INT
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.
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.
- la opción
-Xrs
especificada / no especificada - la propiedad
ibm.signalhandling.sigint
establecida entrue
/false
- la propiedad
ibm.signalhandling.rs
establecida enSIGINT
/ <=>
(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:
- en el enlace a continuación
- Capturando SIGINT en una aplicación Java en UNIX
- Verificar señal manejo, encadenamiento de señales nativas
- JDK 6 HotSpot VM - Manejo de señales en el sistema operativo Solaris y Linux
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.