2009-06-26 26 views
5

Tôi đang điều tra một vấn đề Java (sử dụng IBM JVM 1.4.2 64-bit) trên Red Hat Linux. Tôi tự hỏi nếu có ai đã nhìn thấy thông báo lỗi này trước và biết nếu có một giải pháp cho vấn đề này?Lỗi Java: java.lang.IllegalArgumentException: Tín hiệu đã được VM sử dụng: INT

Nguồn:

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

Output:

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 

Thông tin bổ sung:

tôi phát hiện ra một cái gì đó kỳ lạ. Lý do tại sao nó không thành công là vì tôi đang chạy chương trình bên trong một kịch bản lệnh vỏ làm quá trình nền.

tức sigtest.sh:

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

Nếu tôi chạy chương trình từ dòng lệnh, hoặc loại bỏ các "&" (tức là làm cho nó một quá trình foreground bên trong shell script), nó không có vấn đề ... Tôi không hiểu tại sao lại như vậy.

+0

Jin, đưa ra nhận xét của bạn về câu trả lời của tôi, JVM không cho phép bạn đăng ký một móc trong sự kiện này. Bạn có thể mô tả thêm về những gì bạn đang cố gắng thực hiện không? Có thể có một cách để làm điều đó đồng bộ hơn với kỳ vọng của JVM. – Yishai

+0

Tôi muốn chương trình thoát ra một cách duyên dáng bằng cách chạy một số mã "dọn sạch" nếu nó bị gián đoạn. –

+0

Vấn đề là JVM cụ thể. Tôi đã trao tiền thưởng cho Jitter, vì câu trả lời của ông bao gồm "triển khai JVM cụ thể" và cung cấp hầu hết các công cụ để chẩn đoán vấn đề của tôi. Cảm ơn mọi người. –

Trả lời

3

Đây có thể là vấn đề cụ thể về triển khai JVM. Chúng tôi đang sử dụng API không được tài liệu/không được hỗ trợ (sun.misc.Signal/SignalHandler) và do đó không có hợp đồng về hành vi của API được đảm bảo.

Việc triển khai JVM của IBM có thể thực hiện các việc liên quan đến xử lý tín hiệu khác với triển khai JVM SUN và do đó gây ra sự cố này. Vì vậy, trường hợp sử dụng cụ thể này hoạt động trong JVM SUN nhưng không hoạt động trong JVM của IBM.

Nhưng thử như sau (tôi không thể thử nó ra bản thân mình):

Có phải tất cả kết hợp off bắt đầu JVM với một/hai/ba của những tham số và có kết hợp giá trị càng tốt.

  1. tùy chọn -Xrs định/không quy định
  2. tài sản ibm.signalhandling.sigint thiết lập để true/false
  3. tài sản ibm.signalhandling.rs thiết lập để true/false

(Các thuộc tính nơi tìm thấy qua google trong vài lỗi bãi chứa nhưng tôi không thể tìm thấy bất kỳ tài liệu cụ thể nào về chúng)

Tôi không biết nếu IBM JVM cũng hỗ trợ cờ đặc biệt này nhưng bạn có thể thử thêm này quá mà trong SUN JVM có vẻ là cụ thể đối với một số vấn đề với bộ xử lý tín hiệu dưới Linux/solaris

-XX:-AllowUserSignalHandlers 

Hoặc thử sử dụng trình xử lý tín hiệu gốc nếu đó là tùy chọn cho bạn. Kiểm tra các mẫu mã được cung cấp:

Mặc dù nó không liên quan đến vấn đề cụ thể của bạn, một bài báo trên IBM JVM xử lý tín hiệu (hơi ngày nhưng vẫn chủ yếu là chính xác). Với mẫu để xử lý tín hiệu mã gốc:

Revelations on Java signal handling and termination


Nhưng tôi đoán tất cả điều này có thể không có kết quả như việc thực hiện IBM JVM có thể dựa vào xử lý SIGINT bản thân để hoạt động tốt và do đó không bao giờ đem lại cho bạn một cơ hội để tự mình xử lý SIGINT.

Btw. từ description to the -Xrs flag Tôi hiểu rằng nó thực sự có thể cản trở bạn làm những gì bạn muốn. Nó nói

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.

Hoặc nó có thể có nghĩa là chỉ các hành động mặc định JVM cho tín hiệu không được thực thi. Hoặc nó có thể phụ thuộc vào việc thực hiện JVM những gì thực sự có nghĩa là.

+0

Vấn đề là JVM cụ thể. Tôi đã phải cài đặt một JVM khác để có được hành vi mà tôi mong muốn. –

0

Trường hợp ngoại lệ xảy ra do VM đã có trình xử lý tín hiệu được đặt cho SIGINT. Những gì bạn có thể/nên làm về điều này phụ thuộc vào bối cảnh trong đó ngoại lệ này được ném.

0

Tôi đã thử cùng một mã và nó hoạt động cho tôi. Vì vậy, tôi đoán có thể có một số khác biệt trong thiết lập.

Sau khi thêm

System.out.println("Hello"); 

vào tin nhắn xử lý tôi có thể chạy các lớp như thế:

[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

Có, tôi có hai môi trường. Một là 32 bit Linux, nó hoạt động tốt bằng cách sử dụng Sun JVM. Một là 64 bit Linux, nó không hoạt động trên cái này. –

+0

Thiết lập của tôi là 64 bit (2.6.24 ...) sử dụng Sun JVM (HotSpot, 1.6.0_11). –

+0

Tôi bắt đầu cảm thấy đây là vấn đề lập trình ít hơn và nhiều vấn đề về JVM hơn. –

2

Hãy thử bắt đầu JVM với một tùy chọn -Xrs có giá trị trên IBM JVM theo this. Điều đó có thể ngăn chặn xung đột.

EDIT: Đáp lại mong muốn cơ bản của bạn, nhìn vào:

Runtime.getRuntime().addShutdownHook(Thread)

Bạn phân lớp một đối tượng thread, và nó sẽ bắt đầu như một phần của shutdown (lấy ra rằng -Xrs cho điều này để làm việc tốt). Một số thứ (như ngừng gọi trên Thời gian chạy) có thể ngăn chặn điều đó xảy ra, vì vậy bạn cần phải nhận thức được khả năng nó sẽ không xảy ra.

+0

Đó thay đổi sản lượng từ: java.lang.IllegalArgumentException như sau: java.lang.IllegalArgumentException

1

Được viết bởi Heinz Kabutz, các tín hiệu bạn có thể bắt phụ thuộc vào hệ điều hành bạn đang chạy và có thể hỗ trợ phiên bản JVM. Nếu một sự kết hợp os/jvm nào đó không cho phép bạn đăng ký tín hiệu thì bạn sẽ không may mắn. Có thể tinh chỉnh với cài đặt os/vm có thể hữu ích.

Theo nhận xét của bạn, thêm shutdown hook theo đề xuất của Yishai nên thực hiện thủ thuật.

0

Tôi đã làm việc này bằng cách sử dụng một triển khai JVM khác (SuSE) thay vì IBM. Khi xử lý các tính năng không có giấy tờ, có vẻ như các JVM không nhất quán trong hành vi.

0

Tôi cũng gặp vấn đề tương tự. Tôi chạy chương trình java từ tập lệnh ksh. Nếu tôi chạy kịch bản với tài khoản trong đó có hồ sơ cá nhân csh tức là, trong file/etc/passwd

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

Tập lệnh sẽ chạy thành công. Nhưng nếu tôi chạy nó với tài khoản có cấu hình không phải là sh, nó sẽ đưa ra cùng một lỗi.

Vì vậy, giải pháp là để hồ sơ người dùng unix của bạn được thay đổi thành csh.

0

Tôi cũng đã gặp phải vấn đề này với IBM JVM (64 bit) trên Linux. Hóa ra là JVM nhạy cảm với mặt nạ tín hiệu của quá trình gọi nó.

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

Lưu ý rằng bit cho SIGINT (giá trị 2) được đặt trong SigIgn. Khi khởi động IBM JVM với mặt nạ này, nó từ chối cài đặt trình xử lý cho SIGINT. Tôi làm việc xung quanh vấn đề bằng cách tung ra các JVM thông qua một wrapper Python mà reset handler SIGINT để mặc định:

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

Đối số đầu tiên vào wrapper là lệnh java, sau đó làm theo các đối số cho JVM.

Các vấn đề liên quan