program story

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

inputbox 2020. 8. 12. 08:15
반응형

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


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

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

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

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


그것은이다 불가능 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"

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

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

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

What I generally do to (for instance) detect abnormal termination is to launch my JVM inside a Perl script, but have the script wait for the JVM using the waitpid system call.

I am then informed whenever the JVM exits, and why it exited, and can take the necessary action.


I would expect that the JVM gracefully interrupts (thread.interrupt()) all the running threads created by the application, at least for signals SIGINT (kill -2) and SIGTERM (kill -15).

This way, the signal will be forwarded to them, allowing a gracefully thread cancellation and resource finalization in the standard ways.

But this is not the case (at least in my JVM implementation: Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode).

As other users commented, the usage of shutdown hooks seems mandatory.

So, how do I would handle it?

Well first, I do not care about it in all programs, only in those where I want to keep track of user cancellations and unexpected ends. For example, imagine that your java program is a process managed by other. You may want to differentiate whether it has been terminated gracefully (SIGTERM from the manager process) or a shutdown has occurred (in order to relaunch automatically the job on startup).

As a basis, I always make my long-running threads periodically aware of interrupted status and throw an InterruptedException if they interrupted. This enables execution finalization in way controlled by the developer (also producing the same outcome as standard blocking operations). Then, at the top level of the thread stack, InterruptedException is captured and appropriate clean-up performed. These threads are coded to known how to respond to an interruption request. High cohesion design.

So, in these cases, I add a shutdown hook, that does what I think the JVM should do by default: interrupt all the non-daemon threads created by my application that are still running:

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

Complete test application at github: https://github.com/idelvall/kill-test


You can use Runtime.getRuntime().addShutdownHook(...), but you cannot be guaranteed that it will be called in any case.


There is one way to react to a kill -9: that is to have a separate process that monitors the process being killed and cleans up after it if necessary. This would probably involve IPC and would be quite a bit of work, and you can still override it by killing both processes at the same time. I assume it will not be worth the trouble in most cases.

Whoever kills a process with -9 should theoretically know what he/she is doing and that it may leave things in an inconsistent state.

참고URL : https://stackoverflow.com/questions/2541597/how-to-gracefully-handle-the-sigkill-signal-in-java

반응형