Java错误:java.lang.IllegalArgumentException:VM已使用的信号:INT

时间:2009-06-26 17:49:57

标签: java jvm signals

我正在调查Red Hat Linux上的Java问题(使用IBM JVM 1.4.2 64位)。 我想知道是否有人之前看过这个错误消息,并知道是否有解决此问题的方法?

来源:

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

输出:

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

其他信息:

我发现了一些奇怪的东西。 它失败的原因是因为我在shell脚本中运行程序作为后台进程。

即。 sigtest.sh:

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

如果我从命令行运行程序,或删除“&amp;” (即将它作为shell脚本中的前台进程),它没有问题...... 我不明白为什么会这样。

8 个答案:

答案 0 :(得分:3)

这很可能是JVM实现特定的问题。我们使用的是未记录/不受支持的API(sun.misc.Signal/SignalHandler),因此无法保证API行为的合同。

IBM JVM实现可以与SUN JVM实现不同地执行与信号处理相关的事情,从而导致此问题。因此,此特定用例适用于SUN JVM,但不适用于IBM JVM。

但尝试以下(我不能自己尝试):

使用这些参数中的一个/两个/三个以及可能的值组合来启动JVM的所有组合。

  1. 指定/未指定-Xrs选项
  2. 属性ibm.signalhandling.sigint设置为true / false
  3. 属性ibm.signalhandling.rs设置为true / false
  4. (通过谷歌在几个错误转储中找到的属性,但我找不到任何特定的文档)

    我不知道IBM JVM是否也支持这个特殊标志,但您也可以尝试添加它,这在SUN JVM中似乎特定于linux / solaris下的信号处理程序的某些问题

    -XX:-AllowUserSignalHandlers
    

    或尝试使用本机信号处理程序,如果这是一个选项。查看提供的代码示例:

    虽然它与您的具体问题无关,但是有关JVM信号处理的IBM文章(稍微陈旧但仍大致正确)。使用本机代码信号处理程序的示例:

    Revelations on Java signal handling and termination


    但我想这可能都无济于事,因为IBM JVM实现可以依赖处理SIGINT本身来正常运行,从而永远不会让你有机会自己处理SIGINT

    顺便说一下。来自description to the -Xrs flag我明白它实际上可能会阻碍你做你想做的事。它说

      

    在Sun的JVM上使用-Xrs时,   SIGINT,SIGTERM的信号掩码,   SIGHUP和SIGQUIT不会改变   JVM和这些的信号处理程序   未安装信号

    或者它可能意味着仅执行信号的JVM默认操作。或者它可能取决于JVM实现的真正含义。

答案 1 :(得分:2)

尝试使用-Xrs选项启动JVM,该选项根据this在IBM JVM上有效。这可能会阻止冲突。

编辑:为了回应你的潜在愿望,请看:

Runtime.getRuntime().addShutdownHook(Thread)

你是一个线程对象的子类,它将作为关闭的一部分启动(取出-Xrs以使其正常工作)。有些事情(比如在运行时调用暂停)可以阻止这种情况发生,因此你需要意识到它不会最终发生的可能性。

答案 2 :(得分:1)

Heinz Kabutz编写,您能够捕获的信号取决于您运行的操作系统以及可能的JVM版本。如果某个os / jvm组合不允许你注册你的信号那么你运气不好。也许使用os / vm设置进行调整可能有所帮助。

根据您的评论,根据Yishai的建议添加shutdown hook应该可以解决问题。

答案 3 :(得分:0)

发生异常是因为VM已经为SIGINT设置了信号处理程序。您可以/应该做些什么取决于抛出此异常的上下文。

答案 4 :(得分:0)

我尝试了相同的代码,它对我有用。所以我想设置可能会有所不同。

添加

System.out.println("Hello");

到句柄消息我可以像这样运行类:

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

答案 5 :(得分:0)

我通过使用不同的JVM实现(SuSE)代替IBM来实现这一点。 处理未记录的功能时,似乎JVM的行为不是很一致。

答案 6 :(得分:0)

我也有同样的问题。我从ksh脚本运行java程序。 如果我使用具有csh配置文件的帐户运行脚本 即在/ etc / passwd文件中

用户X:*:7260:20 :: /家/用户X:在/ usr / bin中/ CSH

该脚本将成功运行。但是,如果我使用除sh配置文件以外的帐户运行它,则会产生相同的错误。

因此,解决方案是将您的unix用户配置文件更改为csh。

答案 7 :(得分:0)

我在Linux上也遇到过IBM JVM(64位)这个问题。事实证明,JVM对调用它的进程的信号掩码很敏感。

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

注意SIGINT(值2)的位在SigIgn中设置。使用此掩码启动IBM JVM时,它拒绝为SIGINT安装处理程序。我通过Python包装器启动JVM解决了这个问题,该包装器将SIGINT处理程序重置为默认值:

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

包装器的第一个参数是java命令,然后遵循JVM的参数。