System.exit()
System.exit()方法用于stop the running Java Virtual Machine,即用于停止JVM。
在停止JVM之前,JVM会执行所有的shutdown钩子程序,这些shutdown钩子是通过Runtime.getRuntime().addShutdownHook()方法注册到IdentityHashMap类型的对象中,一般是在JVM启动的时候进行注册。
当所有的shutdown钩子程序执行完成之后,如果开启了finalization-on-exit,则会运行所有未被触发的finalizers。最终才是停止JVM进程。
此方法实际上调用的也是Runtime.getRuntime().exit()方法,需要一个正整数状态码作为变量,且无返回值,方法声明如下:
public static void exit(int status)
如果状态码非0,表示程序异常停止。
The way to handle this for anything other than kill -9 would be to register a shutdown hook. If you can use (SIGTERM) kill -15 the shutdown hook will work. (SIGINT) kill -2 DOES cause the program to gracefully exit and run the shutdown hooks.
Runtime.getRuntime().halt()
Runtime类允许应用程序执行期间,执行环境(比如操作系统)与应用程序进程进行交互。
Runtime类中的halt方法是用来forcibly terminate the running JVM,即强制终止正在运行的JVM进程。halt方法与exit方法不同的是:halt方法不会触发JVM中shutdown钩子程序的执行。因此,当我们调用halt方法时,shutdown钩子函数和finalizers都不会被执行。halt方法声明如下:
public void halt(int status)
和exit方法类似的是,此方法中的非0状态码表示程序异常终止。
Shutting down an Unix System
During a clean system shutdown, the following actions take place:
(1)All users are notified that the system will be going down, preferably giving them some reasonable advance warning.
(2)All running processes are sent a signal telling them to terminate, allowing them time to exit gracefully, provided the program has made provisions to do so.
(3)All subsystems are shut down gracefully, via the commands they provide for doing so.
(4)All remaining users are logged off, and remaining processes are killed.
(5)Filesystem integrity is maintained by completing all pending disk updates.
(6)Depending on the type of shutdown, the system moves to single-user mode, the processor is halted, or the system is rebooted.
After taking these steps, the administrator can turn the power off, execute diagnostics, or perform other maintenance activities as appropriate.
Unix provides the shutdown command to accomplish all of this. Generally, shutdown sends a series of timed messages to all users who are logged on, warning them that the system is going down; after sending the last of these messages, it logs all users off the system and places the system in single-user mode.
对于发送SIGNAL给进程,以便终止进程的过程,实际上是先发送SIGTERM,如果还未结束,则发送SIGKILL。代码在shutdown.c/main()方法中,如下所示:
disable_coredumps();
log_info("Sending SIGTERM to remaining processes...");
broadcast_signal(SIGTERM, true, true, arg_timeout);
log_info("Sending SIGKILL to remaining processes...");
broadcast_signal(SIGKILL, true, false, arg_timeout);
发送SIGTERM信号时,可能由于某种原因没有进行执行完shutdown钩子函数或者finalizers,超时后会进行下一步,即发送SIGKILL信号。
JVM shutdown过程
JVM执行完main主线程后,需要等待其他非daemon线程执行完毕,然后再执行invoke_shutdown_hooks方法,去回调Java程序注册的ShutdownHooks逻辑。
invoke_shutdown_hooks方法定义在javaThread.cpp中,源码如下所示:
void JavaThread::invoke_shutdown_hooks() {
HandleMark hm(this);
// We could get here with a pending exception, if so clear it now.
if (this->has_pending_exception()) {
this->clear_pending_exception();
}
EXCEPTION_MARK;
Klass* shutdown_klass =
SystemDictionary::resolve_or_null(vmSymbols::java_lang_Shutdown(),
THREAD);
if (shutdown_klass != nullptr) {
// SystemDictionary::resolve_or_null will return null if there was
// an exception. If we cannot load the Shutdown class, just don't
// call Shutdown.shutdown() at all. This will mean the shutdown hooks
// won't be run. Note that if a shutdown hook was registered,
// the Shutdown class would have already been loaded
// (Runtime.addShutdownHook will load it).
JavaValue result(T_VOID);
JavaCalls::call_static(&result,
shutdown_klass,
vmSymbols::shutdown_name(),
vmSymbols::void_method_signature(),
THREAD);
}
CLEAR_PENDING_EXCEPTION;
}