자바 도구 (jmap, jstack) 가 Liux 에서 의 소스 코드 분석 (2) 신호 처리

자바 가상 컴퓨터 가 시 작 될 때 내부 스 레 드 가 많이 시 작 됩 니 다. 이 스 레 드 는 주로 thread. cpp 에 있 는 create 입 니 다.vm 방법 체 에서 실현
thread. cpp 에 서 는 주로 두 개의 스 레 드 를 만들어 신호 와 관련 된 것 을 처리 합 니 다.
  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. 신호 디 스 패 처 스 레 드
os. cpp 에서 의 signalinit () 함수 에서 signal dispatcher 스 레 드 를 시 작 했 습 니 다. signal dispatcher 스 레 드 는 주로 신 호 를 처리 하고 신 호 를 기다 리 며 배포 처 리 를 합 니 다. 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::signalwait();신 호 를 기다 리 고 있 습 니 다. Liux 에 서 는 sem 을 통 해wait () 를 통 해 이 루어 집 니 다. SIGBREAK (Liux 의 QUIT) 신 호 를 받 았 을 때 (신호 처리 에 관 해 서 는 필자 의 다른 블 로그: 자바 에서 신호 처리 가 Liux 에서 이 루어 집 니 다) 를 참고 하 십시오. 처음으로 AttachListener::is 호출 을 통 해init_trigger () attach listener 스 레 드 를 초기 화 합 니 다. 2. Attach Listener 스 레 드 를 참조 하 십시오.
4. 567917. 첫 번 째 신 호 를 받 으 면 초기 화 를 시작 합 니 다. 초기 화 에 성공 하면 바로 돌아 갑 니 다. 또한 스 레 드 stack 의 정 보 를 되 돌려 주지 않 습 니 다 (socket file 을 통 해 되 돌아 갑 니 다). 그리고 두 번 째 는 초기 화 할 필요 가 없습니다.초기 화 에 성공 하지 못 하면 콘 솔 의 outputstream 에서 스 레 드 스 택 정 보 를 직접 인쇄 합 니 다
4. 567917. 두 번 째 신 호 를 받 았 습 니 다. 초기 화 되면 콘 솔 에서 스 레 드 스 택 정 보 를 직접 인쇄 합 니 다.초기 화 되 지 않 으 면 초기 화 를 계속 하고 처음 과 같은 절 차 를 밟 습 니 다
2. 수신 기 스 레 드 첨부
Attach Listener 스 레 드 는 외부 명령 을 받 고 이 명령 을 실행 하 며 결 과 를 발송 자 에 게 되 돌려 줍 니 다.jvm 가 시 작 될 때 + StartAttachListener 가 지정 되 지 않 으 면 이 스 레 드 는 시작 되 지 않 습 니 다. 방금 quit 신 호 를 받 은 후에 AttachListener::is 를 호출 하 는 것 에 대해 논 의 했 습 니 다.init_trigger () 호출 용 AttachListener::init () 를 통 해 Attach Listener 스 레 드 를 시작 하 는 동시에 서로 다른 운영 체제 에서 초기 화 되 었 습 니 다. Liux 에 서 는 attachListener 입 니 다.Linux. cpp 파일 에서 이 루어 졌 습 니 다.
linux 에서 파일 을 발견 하면. attachpid\# pid 가 존재 해 야 attach listener 스 레 드 를 시작 하고 socket 파일 을 초기 화 합 니 다. 즉, 보통 jmap, jstack tool 이 하 는 일 은 attach 를 먼저 만 듭 니 다.pid\# pid 파일 을 보 내 고 quit 신 호 를 보 냅 니 다. 이런 방식 으로 Attach Listener 스 레 드 를 몰래 시 작 했 습 니 다. (블 로그 참조:http://blog.csdn.net/raintungli/article/details/7023092).
스 레 드 구현 은 attachlistener_thread_entry 방법 체 에서 실현
static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
  os::set_priority(thread, NearMaxPriority);

  if (AttachListener::pd_init() != 0) {
    return;
  }
  AttachListener::set_initialized();

  for (;;) {
    AttachOperation* op = AttachListener::dequeue();  
     if (op == NULL) {
      return;   // dequeue failed or shutdown
    }

    ResourceMark rm;
    bufferedStream st;
    jint res = JNI_OK;

    // handle special detachall operation
    if (strcmp(op->name(), AttachOperation::detachall_operation_name()) == 0) {
      AttachListener::detachall();
    } else {
      // find the function to dispatch too
      AttachOperationFunctionInfo* info = NULL;
      for (int i=0; funcs[i].name != NULL; i++) {
        const char* name = funcs[i].name;
        assert(strlen(name) <= AttachOperation::name_length_max, "operation <= name_length_max");
        if (strcmp(op->name(), name) == 0) {
          info = &(funcs[i]);
          break;
        }
      }

      // check for platform dependent attach operation
      if (info == NULL) {
        info = AttachListener::pd_find_operation(op->name());
      }

      if (info != NULL) {
        // dispatch to the function that implements this operation
        res = (info->func)(op, &st);
      } else {
        st.print("Operation %s not recognized!", op->name());
        res = JNI_ERR;
      }
    }

    // operation complete - send result and output to client
    op->complete(res, &st);
  }
}

Attach Listener::dequeue ();liunx 에서 의 실현 은 방금 만 든 socket 파일 을 감청 하 는 것 입 니 다. 요청 이 들 어 오 면 요청 에 대응 하 는 동작 을 찾 고 호출 작업 이 결 과 를 얻어 이 socket 파일 에 결 과 를 기록 합 니 다. socket 파일 을 삭제 하면 jstack/jmap 에 오류 정보 unable to open socket file:.....
 
우 리 는 자주 사용한다. kill - 3 pid 의 작업 은 라인 스 택 정 보 를 인쇄 합 니 다. 구체 적 인 실현 은 Signal Dispatcher 스 레 드 에서 이 루어 진 것 을 볼 수 있 습 니 다. kill - 3 pid 는. attach 를 만 들 지 않 기 때 문 입 니 다.pid\# pid 파일 이 초기 화 되 지 않 아 스 레 드 의 스 택 정보 가 콘 솔 에 인쇄 되 었 습 니 다.

좋은 웹페이지 즐겨찾기