5

我正在调查 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 &

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

4

8 回答 8

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 下的信号处理程序的一些问题

-XX:-AllowUserSignalHandlers

或者,如果您愿意,请尝试使用本机信号处理程序。查看提供的代码示例:

尽管它与您的具体问题无关,但 IBM 的一篇关于 JVM 信号处理的文章(有点过时但仍然大部分正确)。带有本机代码信号处理程序的示例:

Java信号处理与终止的启示


但我想这可能都无济于事,因为 IBM JVM 实现可能依赖于处理SIGINT自身才能正常运行,因此永远不会给你机会处理SIGINT自己。

顺便提一句。从描述到-Xrs标志,我知道它实际上可能会阻碍你做你想做的事。它说

-XrsSun 的 JVM 上使用时,JVM 不会更改 SIGINT、SIGTERM、SIGHUP 和 SIGQUIT 的信号掩码,并且不会安装这些信号的信号处理 程序。

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

于 2009-07-03T15:00:43.657 回答
2

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

编辑:响应您的潜在愿望,请查看:

Runtime.getRuntime().addShutdownHook(线程)

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

于 2009-06-29T19:39:54.030 回答
1

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

根据您的评论,添加Yishai 提出的关闭挂钩应该可以解决问题。

于 2009-06-30T21:36:16.283 回答
0

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

于 2009-06-26T18:09:44.400 回答
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
于 2009-06-29T19:32:07.337 回答
0

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

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

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

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

于 2013-12-05T04:01:00.900 回答
0

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

于 2009-07-06T15:36:02.310 回答
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 的参数。

于 2016-02-19T14:05:25.490 回答