当Java程序运行时出现CPU负载高、内存占用大等异常情况时,通常需要使用JDK自带的工具jstack、jmap查看JVM的运行时数据,并进行分析。
那么JVM自带的这些工具是如何获取到JVM的相关信息呢?
JVM提供了 Java Attach 功能,能够让客户端与目标JVM进行通讯从而获取JVM运行时的数据,甚至可以通过Java Attach 加载自定义的代理工具,实现AOP、运行时class热更新等功能。
如果我们通过jstack打印线程栈的时候会发现有这么2个线程:Signal Dispatcher和Attach Listener。
- "Signal Dispatcher" #4 daemon prio=9 os_prio=2 cpu=0.00ms elapsed=917.19s tid=0x00000164ff377000 nid=0x4ba0 runnable [0x0000000000000000]
- java.lang.Thread.State: RUNNABLE
-
- "Attach Listener" #5 daemon prio=5 os_prio=2 cpu=0.00ms elapsed=917.19s tid=0x000001648f4d1800 nid=0x1fc0 waiting on condition [0x0000000000000000]
- java.lang.Thread.State: RUNNABLE
Signal Dispatcher用于处理操作系统信号(软中断信号),Attach Listener线程用于JVM进程间的通信。
操作系统支持的信号可以通过kill -l查看。比如我们平时杀进程用kill -9 可以看到9对应的信号就是SIGKILL。
其他的信号并不会杀掉JVM进程,而是通知到进程, 具体进程如何处理根据Signal Dispatcher线程处理逻辑决定。
- root@DESKTOP-45K54QO:~# kill -l
- 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
- 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
- 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
- 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
- 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
- 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
- 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
- 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
- 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
- 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
- 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
- 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
- 63) SIGRTMAX-1 64) SIGRTMAX
在虚拟机初始完成后,Signal Dispatcher和Attach Listener线程会根据配置进行必要的初始化。
- jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
- ...
- //记录虚拟机初始化完成时间
- Management::record_vm_init_completed();
- ...
- // 初始化Signal Dispatcher
- os::signal_init();
-
- // 当设置了StartAttachListener或者无法懒加载时启动Attach Listener
- if (!DisableAttachMechanism) {
- AttachListener::vm_start();
- if (StartAttachListener || AttachListener::init_at_startup()) {
- AttachListener::init();
- }
- }
- ...
- // 通知所有的 JVMTI agents 虚拟机初始化完成
- JvmtiExport::post_vm_initialized();
- ...
- }
-
JVM相关参数如下,默认都是false
| JVM参数 |
默认值 |
| DisableAttachMechanism |
false |
| StartAttachListener |
false |
| ReduceSignalUsage |
false |
除了这三个参数以外,我们可以看到
AttachListener::init_at_startup()也是用于控制Attach Listener是否初始化。
JDK设计的时候根据不同的操作系