프로그램이 종료 신호를 받으면 정리를 어떻게 처리합니까?
예를 들어, 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의 및 운영 체제의 영역으로 뛰어해야 신호를.
예를 들어 비정상 종료를 감지하기 위해 일반적으로 수행하는 작업은 Perl 스크립트 내에서 JVM을 시작하지만 스크립트가 waitpid
시스템 호출을 사용하여 JVM을 기다리도록하는 것 입니다.
그런 다음 JVM이 종료 될 때마다 및 종료 된 이유를 알려주고 필요한 조치를 취할 수 있습니다.
답변
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
답변
사용할 수 Runtime.getRuntime().addShutdownHook(...)
있지만 어떤 경우 에도 호출 될 것이라는 보장은 없습니다 .
답변
kill -9에 대응하는 한 가지 방법이 있습니다. 즉, 종료되는 프로세스를 모니터링하고 필요한 경우 정리하는 별도의 프로세스를 갖는 것입니다. 이것은 아마도 IPC를 포함하고 꽤 많은 작업이 될 것이며, 동시에 두 프로세스를 종료함으로써 여전히 그것을 무시할 수 있습니다. 대부분의 경우 문제가되지 않을 것이라고 생각합니다.
-9로 프로세스를 죽이는 사람은 이론적으로 자신이 무엇을하고 있는지 그리고 일관되지 않은 상태가 될 수 있음을 알아야합니다.