JVM Thread/Stack Memory Size
-Xss1024K
JVM Thread/Stack Object states
(6 states)
new
new Thread()
runnable
java.lang.Thread.start()
blocked
syncronized + java.lang.Object.wait()
waiting
java.lang.Object.wait()
java.lang.Thread.join()
java.util.concurrent.locks.LockSupport.park()
timed_waiting 时间过后自动恢复
java.lang.Thread.sleep(long time)
java.lang.Object.wait(long timeout)
java.lang.Thread.join(long millis)
java.util.concurrent.locks.LockSupport.packNanos(long nanos)
java.util.concurrent.locks.LockSupport.packUntil(long deadline)
terminated
java.lang.Thread.start()方法结束,在内存中的Thread堆对象状态。注意该Thread不能重新start()。
(对应OS的实际线程状态为: new ready running waiting terminated, ready+running=java's runnable)
JVM Thread/Stack Number
(JVM 8, at least 15 threads)
6 no-Java System Threads
VM Thread: 1
VM Periodic Task Thread:1
GC task Thread#n (ParallelGC): 4
8 Java System Threads
Reference Handler: 1
Finalizer: 1
Signal Dispatcher: 1
C1 CompilerThreadn:1
C2 CompilerThreadn:2
Service Thread: 1
Attach Listener: 1
1~n Java User Threads
* main:1
* xxxxxx: 0~n
JVM Thread/Stack Structure
结构:{JVM Stack [Frame][Frame][Frame]... }
- JVM Stack在每个线程被创建时被创建,用来存放一组栈帧(StackFrame/Frame)
- JVM Statck的大小可以是固定的,也可以是动态扩展的。
- 如果线程需要一个比固定大小大的Stack,会发生StackOverflowError
- 如果动态扩展Stack时没有足够的内存或者系统没有足够的内存为新线程创建Stack,发生OutOfMemoryError。
JVM Thread/Stack Frame
结构:{Frame [ReturnValue] [LocalVariables[][][][]...] [OperandStack [][][]...] [ConstPoolRef] }
每次方法调用均会创建一个对应的Frame,方法执行完毕或者异常终止,Frame被销毁。一个方法A调用另一个方法B时,A的frame停止,新的frame被创建赋予B,执行完毕后,把计算结果传递给A,A继续执行。
- 返回值(Returen Value)
- 局部变量表(Local Variables)
- 局部变量表的大小在编译期就被确定。基元类型数据以及引用和返回地址(returnAddress)占用一个局部变量大小,long/double需要两个。
Java代码:
int a=0;
int b=1;
int c=2;
对应的局部变量表:
LocalVariableTable: Start Length Slot Name Signature 2 12 0 a I 4 10 1 b I 6 8 2 c I
局部变量表说明:
Start: 变量偏移量。
Length: 作用域范围长度。[Start,Start+Length)就是该变量的作用域。
Slot: 一个Slot能存储32bit的数据类型、引用、返回地址,long/dobule需要两个Slot
Name: 变量名
Signature: 字节码签名
- 操作栈(Operand Stack)
- Frame被创建时,操作栈是空的。操作栈的每个项可以存放JVM的各种类型数据,包括long/double。
- 操作栈有个栈深,long/double贡献两个栈深。
- 操作栈调用其它有返回结果的方法时,会把结果push到栈上。
Java代码:
int a=1; int b=2; int c=a+b;
对应的指令:
0: iconst_1 // push 1到操作栈。大于5的int值会用到 bipush <i> 指令。 1: istore_0 // pop 顶元素,存储到index=0的本地变量。 2: iconst_2 // push 2 到操作栈 3: istore_1 // pop栈顶元素,存储到index=1的本地变量。 4: iload_0 // 把index=0的本地变量加载到栈顶 5: iload_1 // 把index=1的本地变量加载到栈顶 6: iadd // 把栈顶两个数pop出来相加,并把结果存放到栈顶 7: istore_2 // 结果存储到index=2的本地变量
- 常量池引用(Const Pool Ref)
Dump JVM Thread/Stack States(jstack/jconsole/jvisualvm/mat)
- Thread/Stack状态
- runnable 运行中
- java.lang.Thread.State: RUNNABLE
- waiting on condition 等待资源
- java.lang.Thread.State: RUNNABLE
- java.lang.Thread.State: WAITING (parking)
- java.lang.Thread.State: TIMED_WAITING (parking)
- Object.wait() 处于等待队列里的线程
- java.lang.Thread.State: WAITING (on object monitor)
- java.lang.Thread.State: TIMED_WAITING (on object monitor)
- waiting on monitor entry 进入了临界区,但等待获取监视器
- java.lang.Thread.State: BLOCKED (on object monitor)
- runnable 运行中
Dump JVM Thread/Stack 线程/栈的运行快照
Input(jstack/jconsole/jvisualvm/mat):
jstack jvm_pid
or
jstack -m jvm_pid
Output:
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.102-b14 mixed mode):
"Attach Listener" #32 daemon prio=9 os_prio=0 tid=0x00007f490c001000 nid=0x2b70 waiting on condition [0x0000000000000000]
"RfbReceiverTask" #31 prio=6 os_prio=0 tid=0x00007f48e4168800 nid=0xdcd runnable [0x00007f48cbbfc000]
"RfbSenderTask" #30 prio=6 os_prio=0 tid=0x00007f48e4166800 nid=0xdcc waiting on condition [0x00007f48cbcfd000]
"Thread-3" #28 prio=6 os_prio=0 tid=0x00007f48e415c000 nid=0xdca waiting on condition [0x00007f4928377000]
"SwingWorker-pool-1-thread-6" #26 daemon prio=5 os_prio=0 tid=0x00007f48e4159000 nid=0xdc6 waiting on condition [0x00007f4928478000]
"SwingWorker-pool-1-thread-5" #25 daemon prio=5 os_prio=0 tid=0x00007f48e4157000 nid=0xdc5 waiting on condition [0x00007f4928579000]
"SwingWorker-pool-1-thread-4" #24 daemon prio=5 os_prio=0 tid=0x00007f48e4154000 nid=0xdad waiting on condition [0x00007f492867a000]
"SwingWorker-pool-1-thread-3" #23 daemon prio=5 os_prio=0 tid=0x00007f48e414d000 nid=0xd76 waiting on condition [0x00007f492877b000]
"SwingWorker-pool-1-thread-2" #21 daemon prio=5 os_prio=0 tid=0x00007f48e4147000 nid=0xb73 waiting on condition [0x00007f492887c000]
"SwingWorker-pool-1-thread-1" #20 daemon prio=5 os_prio=0 tid=0x00007f48e413f800 nid=0xb5f waiting on condition [0x00007f4928e7e000]
"Timer-0" #18 daemon prio=6 os_prio=0 tid=0x00007f48e40df800 nid=0xb49 in Object.wait() [0x00007f4928d7d000]
"DestroyJavaVM" #16 prio=5 os_prio=0 tid=0x00007f4948009800 nid=0xb35 waiting on condition [0x0000000000000000]
"AWT-EventQueue-0" #14 prio=6 os_prio=0 tid=0x00007f4948357000 nid=0xb47 waiting on condition [0x00007f4929d34000]
"AWT-Shutdown" #15 prio=5 os_prio=0 tid=0x00007f4948355800 nid=0xb46 in Object.wait() [0x00007f4929e35000]
"AWT-XAWT" #13 daemon prio=6 os_prio=0 tid=0x00007f4948321000 nid=0xb45 runnable [0x00007f492a136000]
"Java2D Disposer" #11 daemon prio=10 os_prio=0 tid=0x00007f4948300800 nid=0xb44 in Object.wait() [0x00007f492a64e000]
"TimerQueue" #10 daemon prio=5 os_prio=0 tid=0x00007f4948298000 nid=0xb43 waiting on condition [0x00007f492abe6000]
"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x00007f494819a000 nid=0xb41 runnable [0x0000000000000000]
"C1 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f4948185000 nid=0xb40 waiting on condition [0x0000000000000000]
"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f4948183000 nid=0xb3f waiting on condition [0x0000000000000000]
"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f4948180000 nid=0xb3e waiting on condition [0x0000000000000000]
"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f494817e800 nid=0xb3d runnable [0x0000000000000000]
"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f494814b000 nid=0xb3c in Object.wait() [0x00007f493148d000]
"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f4948146000 nid=0xb3b in Object.wait() [0x00007f493158e000]
"VM Thread" os_prio=0 tid=0x00007f494813e800 nid=0xb3a runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f494801f000 nid=0xb36 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f4948020800 nid=0xb37 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f4948022800 nid=0xb38 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f4948024000 nid=0xb39 runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007f49481ad000 nid=0xb42 waiting on condition
JVisualVM
JVM state -> JVisualVM show state
BLOCKED -> Monitor
RUNNABLE -> Running
WAITING/TIMED_WAITING -> Sleeping/Park/Wait
TERMINATED/NEW -> Zombie
JVisualVM show state
Monitor: threads are waiting on a condition to become true to resume execution
Running: thread is still running.
Sleeping: thread is sleeping (method yield() was called on the thread object)
Wait: thread was blocked by a mutex or a barrier, and is waiting for another thread to release the lock
Park: parked threads are suspended until they are given a permit. Unparking a thread is usually done by calling method unpark() on the thread object
Sleeping and Park are specific cases of (timed) waiting:
Sleeping: specifically waiting in Thread.sleep().
Park: specifically waiting in sun.misc.Unsafe.park() (presumably via LockSupport).
Dump OS Thread/Stack OS的线程运行状态
Iuput(top):
top -Hp jvm_pid
Output:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2868 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.00 java
2869 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.67 java
2870 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:01.37 java
2871 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:01.36 java
2872 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:01.35 java
2873 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:01.38 java
2874 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:03.85 java
2875 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.10 java
2876 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.00 java
2877 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.00 java
2878 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:09.96 java
2879 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:09.20 java
2880 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:03.71 java
2881 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.00 java
2882 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:29.08 java
2883 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.14 java
2884 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.19 java
2885 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 5:29.83 java
2886 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.00 java
2887 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 66:06.53 java
2889 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.36 java
2911 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.01 java
2931 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.00 java
3446 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.00 java
3501 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.00 java
3525 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.00 java
3526 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.34 java
3530 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:33.47 java
3532 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:12.16 java
3533 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 22:27.11 java
11120 zhaomeng 20 0 4334856 166220 6720 S 0.0 4.8 0:00.00 java
or input(ps):
ps -mp 31861 -o THREAD,tid,time | sort -rn
Dump Thread/Stack Analysis
- 注意thread/stack的命名,尤其是线程池的名字,切忌使用默认名字。(自己在创建线程或者使用线程池创建线程时,一定要取一个有意义的名字,方便分析,对于Thread-1或者pool-1-thread-1这样的名字,很难第一眼明白它是干什么用的)
- jstack显示的thread id(nid)是16进制,对应的os显示的thread id(pid)为10进制,换算一下就可以对应起来
- 通过top -Hp可以看到每一个线程的id(PID)、实时CPU使用率(%CPU)、CPU占用总时间(TIME+)
- 从上面jstack的输出和top的输出可以看出线程2887(0xB47) "AWT-EventQueue-0" 占用了66mins(超过70%的cpu时间),3533(0xDCD)"RfbReceiverTask"占用了22mins(接近20%的cpu时间),其他线程基本没有占用cpu.
Attach to JVM(Ubuntu)
sudo vi /etc/sysctl.d/10-ptrace.conf
kernel.yama.ptrace_scope = 0
then reboot
or
sudo vi /proc/sys/kernel/yama/ptrace_scope
0
or
echo 0|sudo tee /proc/sys/kernel/yama/ptrace_scope
or
echo 0 > /proc/sys/kernel/yama/ptrace_scope