Java 工具(jmap,jstack)在Linux上的源码分析(二)信号处理
Java 工具(jmap,jstack)在Linux上的源码分析(二)信号处理
当java虚拟机启动的时候,会启动很多内部的线程,这些线程主要在thread.cpp里的create_vm方法体里实现
而在thread.cpp里主要起了2个线程来处理信号相关的
- JvmtiExport::enter_live_phase();
- // Signal Dispatcher needs to be started before VMInit event is posted
- os::signal_init();
- // Start Attach Listener if +StartAttachListener or it can't be started lazily
- if (!DisableAttachMechanism) {
- if (StartAttachListener || AttachListener::init_at_startup()) {
- AttachListener::init();
- }
- }
1. Signal Dispatcher 线程
在os.cpp中的signal_init()函数中,启动了signal dispatcher 线程,对signal dispather 线程主要是用于处理信号,等待信号并且分发处理,可以详细看signal_thread_entry的方法
- static void signal_thread_entry(JavaThread* thread, TRAPS) {
- os::set_priority(thread, NearMaxPriority);
- while (true) {
- int sig;
- {
- // FIXME : Currently we have not decieded what should be the status
- // for this java thread blocked here. Once we decide about
- // that we should fix this.
- sig = os::signal_wait();
- }
- if (sig == os::sigexitnum_pd()) {
- // Terminate the signal thread
- return;
- }
- switch (sig) {
- case SIGBREAK: {
- // Check if the signal is a trigger to start the Attach Listener - in that
- // case don't print stack traces.
- if (!DisableAttachMechanism && AttachListener::is_init_trigger()) {
- continue;
- }
- // Print stack traces
- // Any SIGBREAK operations added here should make sure to flush
- // the output stream (e.g. tty->flush()) after output. See 4803766.
- // Each module also prints an extra carriage return after its output.
- VM_PrintThreads op;
- VMThread::execute(&op);
- VM_PrintJNI jni_op;
- VMThread::execute(&jni_op);
- VM_FindDeadlocks op1(tty);
- VMThread::execute(&op1);
- Universe::print_heap_at_SIGBREAK();
- if (PrintClassHistogram) {
- VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */,
- true /* need_prologue */);
- VMThread::execute(&op1);
- }
- if (JvmtiExport::should_post_data_dump()) {
- JvmtiExport::post_data_dump();
- }
- break;
- }
- default: {
- // Dispatch the signal to java
- HandleMark hm(THREAD);
- klassOop k = SystemDictionary::resolve_or_null(vmSymbolHandles::sun_misc_Signal(), THREAD);
- KlassHandle klass (THREAD, k);
- if (klass.not_null()) {
- JavaValue result(T_VOID);
- JavaCallArguments args;
- args.push_int(sig);
- JavaCalls::call_static(
- &result,
- klass,
- vmSymbolHandles::dispatch_name(),
- vmSymbolHandles::int_void_signature(),
- &args,
- THREAD
- );
- }
- if (HAS_PENDING_EXCEPTION) {
- // tty is initialized early so we don't expect it to be null, but
- // if it is we can't risk doing an initialization that might
- // trigger additional out-of-memory conditions
- if (tty != NULL) {
- char klass_name[256];
- char tmp_sig_name[16];
- const char* sig_name = "UNKNOWN";
- instanceKlass::cast(PENDING_EXCEPTION->klass())->
- name()->as_klass_external_name(klass_name, 256);
- if (os::exception_name(sig, tmp_sig_name, 16) != NULL)
- sig_name = tmp_sig_name;
- warning("Exception %s occurred dispatching signal %s to handler"
- "- the VM may need to be forcibly terminated",
- klass_name, sig_name );
- }
- CLEAR_PENDING_EXCEPTION;
- }
- }
- }
- }
- }
可以看到通过os::signal_wait();等待信号,而在linux里是通过sem_wait()来实现,接受到SIGBREAK(linux 中的QUIT)信号的时候(关于信号处理请参考笔者的另一篇:Java 中关于信号的处理在Linux下的实现 ),第一次通过调用 AttachListener::is_init_trigger()初始化attach listener线程,详细见2.Attach Listener 线程。
- 第一次收到信号,会开始初始化,当初始化成功,将会直接返回,而且不返回任何线程stack的信息(通过socket file的操作返回),并且第二次将不在需要初始化。如果初始化不成功,将直接在控制台的outputstream中打印线程栈信息。
- 第二次收到信号,如果已经初始化过,将直接在控制台中打印线程的栈信息。如果没有初始化,继续初始化,走和第一次相同的流程。
|
评论暂时关闭