我正在调查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脚本中的前台进程),它没有问题...... 我不明白为什么会这样。
答案 0 :(得分:3)
这很可能是JVM实现特定的问题。我们使用的是未记录/不受支持的API(sun.misc.Signal/SignalHandler
),因此无法保证API行为的合同。
IBM JVM实现可以与SUN JVM实现不同地执行与信号处理相关的事情,从而导致此问题。因此,此特定用例适用于SUN JVM,但不适用于IBM JVM。
但尝试以下(我不能自己尝试):
使用这些参数中的一个/两个/三个以及可能的值组合来启动JVM的所有组合。
-Xrs
选项ibm.signalhandling.sigint
设置为true
/ false
ibm.signalhandling.rs
设置为true
/ false
(通过谷歌在几个错误转储中找到的属性,但我找不到任何特定的文档)
我不知道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的参数。