前情提要
在前面已经介绍过 System与initializeSystemClass 在此不做过多解释,没有看到的希望去查看!
System源码浅析- initializeSystemClass(initProperties)
System源码浅析- initializeSystemClass(saveAndRemoveProperties)
System源码浅析- initializeSystemClass(setXXX0)
System源码浅析- initializeSystemClass(loadLibrary)
System源码浅析- initializeSystemClass(setup)
System源码浅析- initializeSystemClass( setJavaLangAccess)
setup
/*
setup 和 teardown 的调用已经在关闭锁上同步了,所以这里不需要进一步同步
*/
static void setup() {
if (handler != null) return;
SignalHandler sh = new SignalHandler() {
public void handle(Signal sig) {
Shutdown.exit(sig.getNumber() + 0200);
}
};
handler = sh;
// When -Xrs is specified the user is responsible for
// ensuring that shutdown hooks are run by calling
// System.exit()
try {
Signal.handle(new Signal("INT"), sh);
} catch (IllegalArgumentException e) {
}
try {
Signal.handle(new Signal("TERM"), sh);
} catch (IllegalArgumentException e) {
}
}
exit
/*
由执行所有安全检查的 Runtime.exit 调用。也由系统提供的终止事件的处理程序调用,它应该传递一个非零状态代码。
*/
static void exit(int status) {
boolean runMoreFinalizers = false;
synchronized (lock) {
if (status != 0) runFinalizersOnExit = false;
switch (state) {
case RUNNING: /* Initiate shutdown */
state = HOOKS;
break;
case HOOKS: /* Stall and halt */
break;
case FINALIZERS:
if (status != 0) {
/* Halt immediately on nonzero status */
halt(status);
} else {
/* Compatibility with old behavior:
* Run more finalizers and then halt
*/
runMoreFinalizers = runFinalizersOnExit;
}
break;
}
}
if (runMoreFinalizers) {
runAllFinalizers();
halt(status);
}
synchronized (Shutdown.class) {
/* 在类对象上同步,导致任何其他尝试启动关闭的线程无限期停止
*/
sequence();
halt(status);
}
}
halt
/*
暂停方法在暂停锁上同步,以避免损坏关闭时删除文件列表。它调用真正的本机停止方法。
*/
static void halt(int status) {
synchronized (haltLock) {
halt0(status);
}
}
Java_java_lang_Shutdown_halt0
JNIEXPORT void JNICALL
Java_java_lang_Shutdown_halt0(JNIEnv *env, jclass ignored, jint code)
{
JVM_Halt(code);
}
JVM_Halt
JVM_ENTRY_NO_ENV(void, JVM_Halt(jint code))
before_exit(thread);
vm_exit(code);
JVM_END
before_exit
// Note: before_exit() can be executed only once, if more than one threads
// are trying to shutdown the VM at the same time, only one thread
// can run before_exit() and all other threads must wait.
void before_exit(JavaThread * thread) {
#define BEFORE_EXIT_NOT_RUN 0
#define BEFORE_EXIT_RUNNING 1
#define BEFORE_EXIT_DONE 2
static jint volatile _before_exit_status = BEFORE_EXIT_NOT_RUN;
// 注意:不要使用 Mutex 来保护整个 before_exit(),
// 因为 JVMTI post_thread_end_event 和 post_vm_death_event 将运行本机代码。
// CAS 或 OSMutex 可以正常工作,但是我们需要为 Safepoint 操作线程状态。
// 这里我们使用 Monitor wait() 和 notify_all() 进行同步。
{ MutexLocker ml(BeforeExit_lock);
switch (_before_exit_status) {
case BEFORE_EXIT_NOT_RUN:
_before_exit_status = BEFORE_EXIT_RUNNING;
break;
case BEFORE_EXIT_RUNNING:
while (_before_exit_status == BEFORE_EXIT_RUNNING) {
BeforeExit_lock->wait();
}
assert(_before_exit_status == BEFORE_EXIT_DONE, "invalid state");
return;
case BEFORE_EXIT_DONE:
return;
}
}
// 主要是关闭之前的一些准备工作。
// 这个和 Win32 的 _onexit procs 之间的唯一区别是这个版本在任何线程被杀死之前被调用。
ExitProc* current = exit_procs;
while (current != NULL) {
ExitProc* next = current->next();
current->evaluate();
delete current;
current = next;
}
// 如果我们报告错误,则在退出时永远挂起。
if (ShowMessageBoxOnError && is_error_reported()) {
os::infinite_sleep();
}
// 终止观察者线程 - 必须在取消注册任何周期性任务之前
if (PeriodicTask::num_tasks() > 0)
WatcherThread::stop();
// 收集的打印统计信息(分析...)
if (Arguments::has_profile()) {
FlatProfiler::disengage();
FlatProfiler::print(10);
}
// 关闭 StatSampler 任务
StatSampler::disengage();
StatSampler::destroy();
// 停止并发 GC 线程
Universe::heap()->stop();
// 打印 GC/heap 相关信息。
if (PrintGCDetails) {
Universe::print();
AdaptiveSizePolicyOutput(0);
if (Verbose) {
ClassLoaderDataGraph::dump_on(gclog_or_tty);
}
}
if (PrintBytecodeHistogram) {
BytecodeHistogram::print();
}
if (JvmtiExport::should_post_thread_life()) {
JvmtiExport::post_thread_end(thread);
}
EventThreadEnd event;
if (event.should_commit()) {
event.set_thread(JFR_THREAD_ID(thread));
event.commit();
}
JFR_ONLY(Jfr::on_vm_shutdown();)
// 即使还没有 JVMTI 环境也总是调用,因为环境可能会延迟附加,并且 JVMTI 必须跟踪 VM 执行的阶段
JvmtiExport::post_vm_death();
Threads::shutdown_vm_agents();
// 终止信号线程 注意:我们不会等到它真正死掉。
os::terminate_signal_thread();
print_statistics();
Universe::heap()->print_tracing_info();
{ MutexLocker ml(BeforeExit_lock);
_before_exit_status = BEFORE_EXIT_DONE;
BeforeExit_lock->notify_all();
}
if (VerifyStringTableAtExit) {
int fail_cnt = 0;
{
MutexLocker ml(StringTable_lock);
fail_cnt = StringTable::verify_and_compare_entries();
}
if (fail_cnt != 0) {
tty->print_cr("ERROR: fail_cnt=%d", fail_cnt);
guarantee(fail_cnt == 0, "unexpected StringTable verification failures");
}
}
#undef BEFORE_EXIT_NOT_RUN
#undef BEFORE_EXIT_RUNNING
#undef BEFORE_EXIT_DONE
}
vm_exit
void vm_exit(int code) {
Thread* thread = ThreadLocalStorage::is_initialized() ?
ThreadLocalStorage::get_thread_slow() : NULL;
if (thread == NULL) {
// we have serious problems -- just exit
vm_direct_exit(code);
}
if (VMThread::vm_thread() != NULL) {
// 启动 VM_Exit 操作以将 VM 带到安全点并退出
VM_Exit op(code);
if (thread->is_Java_thread())
((JavaThread*)thread)->set_thread_state(_thread_in_vm);
VMThread::execute(&op);
// 永远不应该到达这里;但万一VM Thread有问题。
vm_direct_exit(code);
} else {
// VM线程不见了,直接退出
vm_direct_exit(code);
}
ShouldNotReachHere();
}
vm_direct_exit
void vm_direct_exit(int code) {
notify_vm_shutdown();
os::wait_for_keypress_at_exit();
::exit(code);
}
handle
public static synchronized SignalHandler handle(Signal var0, SignalHandler var1) throws IllegalArgumentException {
long var2 = var1 instanceof NativeSignalHandler ? ((NativeSignalHandler)var1).getHandler() : 2L;
long var4 = handle0(var0.number, var2);
// SIGFPE SIGBREAK JVM 已经使用过了
if (var4 == -1L) {
throw new IllegalArgumentException("Signal already used by VM or OS: " + var0);
} else {
signals.put(var0.number, var0);
synchronized(handlers) {
SignalHandler var7 = (SignalHandler)handlers.get(var0);
handlers.remove(var0);
if (var2 == 2L) {
handlers.put(var0, var1);
}
if (var4 == 0L) {
return SignalHandler.SIG_DFL;
} else if (var4 == 1L) {
return SignalHandler.SIG_IGN;
} else {
return (SignalHandler)(var4 == 2L ? var7 : new NativeSignalHandler(var4));
}
}
}
}
handle0
private static native long handle0(int var0, long var1);
Java_sun_misc_Signal_handle0
Java_sun_misc_Signal_handle0(JNIEnv *env, jclass cls, jint sig, jlong handler)
{
return ptr_to_jlong(JVM_RegisterSignal(sig, jlong_to_ptr(handler)));
}
JVM_RegisterSignal 这个不同平台会有不同的实现,我这里浅析windows。
JVM_ENTRY_NO_ENV(void*, JVM_RegisterSignal(jint sig, void* handler))
// Copied from classic vm
// signals_md.c 1.4 98/08/23
void* newHandler = handler == (void *)2
? os::user_handler()
: handler;
switch (sig) {
case SIGFPE:
return (void *)-1; /* already used by VM */
case SIGBREAK:
if (!ReduceSignalUsage) return (void *)-1;
/*
以下信号用于 Shutdown Hooks 支持。但是,如果设置了 ReduceSignalUsage (-Xrs),则必须通过 System.exit() 调用 Shutdown Hooks,Java 不允许使用这些信号,并且允许用户为这些信号设置自己的 _native_ handler 并调用 System.exit() 根据需要。 Terminator.setup() 在存在 -Xrs 时避免注册这些信号。
*/
case SHUTDOWN1_SIGNAL:
case SHUTDOWN2_SIGNAL:
if (ReduceSignalUsage) return (void*)-1;
}
void* oldHandler = os::signal(sig, newHandler);
if (oldHandler == os::user_handler()) {
return (void *)2;
} else {
return oldHandler;
}
JVM_END
JVM中的信息标识
/*
*实际信号值。将其他值与信号一起使用会产生 SIG_ERR 返回值。
*
* 注意: SIGINT 在用户按下 Ctrl-C 时产生
* SIGILL 未经测试。
* SIGFPE 似乎不起作用?
* SIGSEGV 没有捕捉到对 NULL 指针的写入(这会关闭您的应用程序;您能说“分段违规核心转储”吗?)。
* SIGTERM 究竟来自什么样的终止请求?
* SIGBREAK 确实是通过按 Ctrl-Break 产生的。
* SIGABRT 是通过调用 abort 产生的。
*/
#define SIGINT 2 /* Interactive attention */
#define SIGILL 4 /* Illegal instruction */
#define SIGFPE 8 /* Floating point error */
#define SIGSEGV 11 /* Segmentation violation */
#define SIGTERM 15 /* Termination request */
#define SIGBREAK 21 /* Control-break */
#define SIGABRT 22 /* Abnormal termination (abort) */
#define NSIG 23 /* maximum signal number + 1 */
os::signal
void* os::signal(int signal_number, void* handler) {
if ((signal_number == SIGBREAK) && (!ReduceSignalUsage)) {
void (*oldHandler)(int) = sigbreakHandler;
sigbreakHandler = (void (*)(int)) handler;
return (void*) oldHandler;
} else {
return (void*)::signal(signal_number, (void (*)(int))handler);
}
}