Java에서 SIGKILL 신호를 정상적으로 처리하는 방법


113

프로그램이 종료 신호를 받으면 정리를 어떻게 처리합니까?

예를 들어, finish로그 아웃 할 때 제 3 자 앱 (내 앱)이 명령 을 보내도록하는 애플리케이션이 있습니다. finish내 앱이으로 파괴되었을 때 그 명령 을 보내는 가장 좋은 말은 무엇입니까 kill -9?

편집 1 : kill -9는 캡처 할 수 없습니다. 수정 해주셔서 감사합니다.

편집 2 :이 경우는 ctrl-c와 동일한 kill을 호출 할 때 일 것입니다.


44
kill -9나에게 의미 : "자신, 파울 프로세스, 너와 떨어져!", 프로세스는 중단 될 것입니다. 바로.
ZoogieZork

11
. 내가 죽 알고 있어요 것을 * 대부분의 nixes도에서 -9 상관없이 어떤 언어가 작성되지 않은 모든 프로그램에 의해 처리 우아하게 차단 될 수 없습니다
대통령 제임스 K. 포크

2
@Begui은 : 다른 사람이 주석하고 대답 한 내용을뿐만 아니라, 경우 귀하의 취소는 X OS는 즉시 * 죽이고 모든 자원이 회복되지 않는 프로그램하여 사용할 -9'ed 죽 음 ... OS가 깨졌습니다.
SyntaxT3rr0r 2010 년

1
kill -9 명령에 대해 맨 페이지는 "9 KILL (잡을 수없고 무시할 수없는 kill)"이라고 더 정확하게 설명합니다. SIGKILL은 응용 프로그램이 아닌 OS에서 처리하는 신호입니다.
user1338062

4
다만 kill같이 Ctrl 키 C와 동일하지 killCtrl 키 C가 SIGINT를 전송하는 반면, SIGTERM를 보낼 송신되는 신호를 지정하지 않고.
alesguzik

답변:


136

그것은이다 불가능 SIGKILL 명령을 처리하기 위해, 어떤 언어, 어떤 프로그램. 따라서 프로그램이 버그가 있거나 악성 일지라도 항상 프로그램을 종료 할 수 있습니다. 그러나 SIGKILL이 프로그램을 종료하는 유일한 방법은 아닙니다. 다른 하나는 SIGTERM을 사용하는 것입니다. 프로그램 그 신호 처리 할 수 있습니다. 프로그램 제어되지만 신속하게 종료하여 신호를 처리 해야합니다 . 컴퓨터가 종료되면 종료 프로세스의 마지막 단계에서 남아있는 모든 프로세스에 SIGTERM을 보내고 해당 프로세스에 몇 초 동안 유예 한 다음 SIGKILL을 보냅니다.

아무것도이 처리하는 방법 다른 이상은 kill -9레지스터하는 것입니다 종료 훅을. ( SIGTERM )을 사용할 수 있으면 kill -15종료 후크가 작동합니다. ( SIGINT는 ) kill -2 합니까 정상적으로 종료에 프로그램 원인과 종료 후크를 실행합니다.

새 가상 머신 종료 후크를 등록합니다.

Java 가상 머신은 두 가지 유형의 이벤트에 대한 응답으로 종료됩니다.

  • 데몬이 아닌 마지막 스레드가 종료되거나 종료 (동등하게 System.exit) 메서드가 호출 될 때 프로그램이 정상적으로 종료됩니다.
  • ^ C 입력과 같은 사용자 인터럽트 또는 사용자 로그 오프 또는 시스템 종료와 같은 시스템 전체 이벤트에 대한 응답으로 가상 머신이 종료됩니다.

나는 OSX 10.6.3에서 다음 테스트 프로그램을 시도하고에 kill -9그것을 않았다 NOT 예상대로 종료 후크를 실행합니다. A의 kill -15않습니다 종료 후크 때마다 실행합니다.

public class TestShutdownHook
{
    public static void main(String[] args) throws InterruptedException
    {
        Runtime.getRuntime().addShutdownHook(new Thread()
        {
            @Override
            public void run()
            {
                System.out.println("Shutdown hook ran!");
            }
        });

        while (true)
        {
            Thread.sleep(1000);
        }
    }
}

kill -9어떤 프로그램에서도 를 정말 우아하게 처리 할 수있는 방법은 없습니다 .

드문 경우지만 가상 머신이 중단 될 수 있습니다. 즉, 완전히 종료하지 않고 실행을 중지 할 수 있습니다. 이는 가상 머신이 외부에서 종료 될 때 발생합니다 (예 : Unix의 SIGKILL 신호 또는 Microsoft Windows의 TerminateProcess 호출).

a를 처리하는 유일한 실제 옵션 kill -9은 다른 감시자 프로그램이 주 프로그램이 사라지거나 래퍼 스크립트를 사용하도록 감시하는 것입니다. ps목록에서 프로그램을 찾는 명령 을 폴링하고 사라 졌을 때 그에 따라 행동 하는 쉘 스크립트로이를 수행 할 수 있습니다.

#!/usr/bin/env bash

java TestShutdownHook
wait
# notify your other app that you quit
echo "TestShutdownHook quit"

12

있습니다 참조 - 특정의 JVM에서 자신의 신호를 처리 할 수있는 방법 핫스팟 JVM에 대한이 문서의 예는.

Sun 내부 sun.misc.Signal.handle(Signal, SignalHandler)메서드 호출을 사용하여 신호 처리기를 등록 할 수도 있지만 JVM에서 사용하는 것과 같 INT거나 TERM같은 신호에는 등록 할 수 없습니다 .

처리 할 수 있는 당신은 JVM의 및 운영 체제의 영역으로 뛰어해야 신호를.

예를 들어 비정상 종료를 감지하기 위해 일반적으로 수행하는 작업은 Perl 스크립트 내에서 JVM을 시작하지만 스크립트가 waitpid시스템 호출을 사용하여 JVM을 기다리도록하는 것 입니다.

그런 다음 JVM이 종료 될 때마다 및 종료 된 이유를 알려주고 필요한 조치를 취할 수 있습니다.


3
및을 사용 하여 캡처 할 있지만 JVM이 디버깅을 위해 예약하거나 OS가 JVM을 즉시 종료하기 때문에 처리 할 수 ​​없습니다 . 둘 중 하나를 처리하려고하면 . INTTERMsun.misc.SignalQUITKILLIllegalArgumentException
dimo414 2015-08-20

12

JVM이 최소한 신호 및 .NET Framework 애플리케이션에 의해 생성 된 모든 실행중인 스레드를 정상적으로 인터럽트 ( thread.interrupt()) 할 것으로 예상합니다 .SIGINT (kill -2)SIGTERM (kill -15)

이런 식으로 신호가 그들에게 전달되어 표준 방식으로 정상적으로 스레드 취소 및 리소스 종료가 가능합니다 .

그러나 이것은 사실이 아닙니다 (적어도 내 JVM 구현에서는 Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode).

다른 사용자가 언급했듯이 종료 후크 의 사용은 필수로 보입니다.

그래서 어떻게 처리할까요?

우선, 모든 프로그램에서 신경 쓰지 않고 사용자 취소 및 예상치 못한 종료를 추적하려는 경우에만 해당됩니다. 예를 들어, Java 프로그램이 다른 사람이 관리하는 프로세스라고 가정 해보십시오. 정상적으로 종료되었는지 ( SIGTERM관리자 프로세스에서) 또는 종료가 발생했는지 (시작시 작업을 자동으로 다시 시작하기 위해) 구별 할 수 있습니다 .

기본적으로 나는 항상 장기 실행 스레드가 주기적으로 중단 된 상태를 인식하고 중단 된 InterruptedException경우 던집니다 . 이를 통해 개발자가 제어하는 ​​방식으로 실행을 완료 할 수 있습니다 (또한 표준 차단 작업과 동일한 결과를 생성 함). 그런 다음 스레드 스택의 최상위 수준에서 InterruptedException캡처되고 적절한 정리가 수행됩니다. 이러한 스레드는 인터럽트 요청에 응답하는 방법을 알고 있도록 코딩되었습니다. 높은 응집력 디자인.

따라서 이러한 경우에는 JVM이 기본적으로 수행해야한다고 생각하는 작업을 수행하는 종료 후크를 추가합니다. 아직 실행중인 내 애플리케이션에서 생성 된 모든 비 데몬 스레드를 중단합니다.

Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
    public void run() {
        System.out.println("Interrupting threads");
        Set<Thread> runningThreads = Thread.getAllStackTraces().keySet();
        for (Thread th : runningThreads) {
            if (th != Thread.currentThread() 
                && !th.isDaemon() 
                && th.getClass().getName().startsWith("org.brutusin")) {
                System.out.println("Interrupting '" + th.getClass() + "' termination");
                th.interrupt();
            }
        }
        for (Thread th : runningThreads) {
            try {
                if (th != Thread.currentThread() 
                && !th.isDaemon() 
                && th.isInterrupted()) {
                    System.out.println("Waiting '" + th.getName() + "' termination");
                    th.join();
                }
            } catch (InterruptedException ex) {
                System.out.println("Shutdown interrupted");
            }
        }
        System.out.println("Shutdown finished");
    }
});

github에서 테스트 신청 완료 : https://github.com/idelvall/kill-test


6

사용할 수 Runtime.getRuntime().addShutdownHook(...)있지만 어떤 경우 에도 호출 될 것이라는 보장은 없습니다 .


12
그러나 kill -9의 경우 거의 확실히 실행되지 않습니다.
James K. Polk 회장

1

kill -9에 대응하는 한 가지 방법이 있습니다. 즉, 종료되는 프로세스를 모니터링하고 필요한 경우 정리하는 별도의 프로세스를 갖는 것입니다. 이것은 아마도 IPC를 포함하고 꽤 많은 작업이 될 것이며, 동시에 두 프로세스를 종료함으로써 여전히 그것을 무시할 수 있습니다. 대부분의 경우 문제가되지 않을 것이라고 생각합니다.

-9로 프로세스를 죽이는 사람은 이론적으로 자신이 무엇을하고 있는지 그리고 일관되지 않은 상태가 될 수 있음을 알아야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.