2009-06-26 109 views
5

我正在Red Hat Linux上调查Java问题(使用IBM JVM 1.4.2 64位)。 我想知道是否有人以前看过这个错误信息,并知道是否有解决这个问题的方法?Java错误:java.lang.IllegalArgumentException:VM已使用的信号:INT

来源:

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 & 

如果我在命令行中运行该程序,或者删除“&”(即使它的shell脚本里面前台进程),这不有问题... 我不明白为什么会出现这种情况。

+0

Jin,考虑到您对我的回答的评论,JVM不会让您在此事件中注册钩子。你能更详细地描述你想要完成的事情吗?也许有一种方法可以更好地与JVM的期望保持同步。 – Yishai 2009-06-29 20:53:43

+0

我想通过运行一些“清理”的代码,如果程序中断,可以优雅地退出程序。 – 2009-06-29 21:03:03

+0

问题是JVM特有的。 我将赏金授予Jitter,因为他的回答包括“特定于JVM实现”,并提供了诊断我的问题的最多工具。 谢谢大家。 – 2009-07-06 15:39:14

回答

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

(其中通过谷歌在几个发现的属性错误转储但我找不到任何具体的文档)

我不知道,如果IBM JVM也支持这种特殊的标志,但你可以尝试添加这也这在SUN JVM似乎是具体的下Linux/Solaris中的一些问题与信号处理

​​

或者试试使用本地信号处理程序,如果这是您的选择。看看提供的代码示例:

  • 虽然不涉及您的具体问题,对JVM的IBM文章信号处理(稍微过时但仍大部分正确)。随着本地代码信号处理程序样本:

    Revelations on Java signal handling and termination


    但我想这都可能是无济于事的IBM JVM实现可以依靠处理SIGINT本身正常工作,因此从来没有给你一个自己处理SIGINT的机会。

    Btw。从description to the -Xrs flag我知道它实际上可能会阻碍你做你想做的事。它说

    When -Xrs is used on Sun's JVM, the signal masks for SIGINT, SIGTERM, SIGHUP, and SIGQUIT are not changed by the JVM, and signal handlers for these signals are not installed.

    或者这可能意味着只有JVM默认的信号动作才会执行。或者它可能取决于JVM实现的真正含义。

  • 0

    发生异常是因为VM已经为SIGINT放置了信号处理程序。你可以/应该做什么取决于引发这个异常的上下文。

    0

    我试过相同的代码,它适用于我。所以我想这在设置上可能会有一些差异。

    加入

    System.out.println("Hello"); 
    

    到手柄消息后,我可以运行的类这样的:

    [email protected]:/tmp/so$ java SignalTest & sleep 1s && kill -2 $! 
    [1] 20467 
    [email protected]:/tmp/so$ Hello 
    [email protected]:/tmp/so$ 
    [email protected]:/tmp/so$ java SignalTest 
    [1]+ Done    java SignalTest 
    
    +0

    是的,我有两种环境。 一个是32位的Linux,使用Sun JVM可以正常工作。 一个是64位的Linux,它不适用于这个。 – 2009-06-29 19:35:49

    2

    尝试与有效上根据IBM JVM的-Xrs选项启动JVM无论如何,我们都需要this。这可能会阻止冲突。

    编辑:在回答你的潜在欲望,看看:

    ​​

    你继承一个线程对象,并开始为关机(拿那-Xrs这个工作的一部分好)。有些事情(比如在运行时调用halt)可以阻止这种情况的发生,所以您需要意识到它不会最终发生的可能性。

    1

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

    根据你的意见,增加一个shutdown hook由宜易建议应该做的伎俩。

    0

    我通过使用不同的JVM实现(SuSE)而不是IBM来实现此目的。 在处理未记录的功能时,看起来JVM在行为上并不一致。

    0

    我也有同样的问题。我从ksh脚本运行java程序。 如果我运行与该帐户拥有csh的轮廓 即在/ etc /脚本passwd文件

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

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

    所以,解决的办法是让你的UNIX用户配置文件改为csh。

    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安装处理程序。我工作围绕这一问题通过了SIGINT处理程序重置为默认一个Python包装启动JVM:

    #!/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的参数。