1、jstack是什么
jstack是java虚拟机自带的一种堆栈跟踪工具。jstack用来打印出给定的java进程ID或者core file或者远程调试服务的java堆栈信息。
主要是用于生成java虚拟机当前时刻的线程快照,线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环,请求外部资源导致的长时间等待等。
线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程在后台做什么事,或者等待什么资源。
jstack的主要作用:帮助定位程序出现问题的原因,如长时间停顿、cpu占用率高等问题。
2、jstack的使用
jstack的使用可以结合top命令查看出当前系统cpu内存使用率最高的进程pid。
jstack的使用步骤为:
1、先使用jps、ps ef|grep java 查看当前Java进程的pid,严重的时候可以使用top命令查看当前系统cpu、内存使用率最高的进程pid。
[root@localhost opt]# top top - 16:24:42 up 51 days, 20:51, 6 users, load average: 2.31, 2.61, 2.82 Tasks: 1283 total, 1 running, 1282 sleeping, 0 stopped, 0 zombie %Cpu(s): 8.7 us, 0.7 sy, 0.0 ni, 90.3 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st KiB Mem : 23083337+total, 12588844+free, 95284000 used, 9660940 buff/cache KiB Swap: 4194300 total, 4194300 free, 0 used. 13450121+avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4017 root 20 0 6675664 4.9g 5868 S 125.2 2.2 94141:37 xxxxx 29938 root 20 0 18.6g 2.5g 13828 S 110.8 1.1 122:35.90 java 12303 root 20 0 6861556 637644 264096 S 33.4 0.3 1537:42 xxxx 3327 root 20 0 2951676 227816 156864 S 4.9 0.1 202:30.71 xxxx 3874 root 20 0 355696 6792 5908 S 3.3 0.0 2660:46 xxxx ......
我们可以看到产生死锁的java进程的pid为29938。
死锁:两个线程互相得到锁1、锁2,然后线程1等待线程2释放锁2,线程2等待线程1释放锁1.两者互相等待释放,于是就产生了死锁。
如何避免死锁产生:
1、按照顺序加锁:线程间加锁的顺序各不一致,就会导致死锁,如果每个线程都按同一个的加锁顺序这样就不会出现死锁。
2、获取锁时限;在每个获取锁的时候加上一个时限,如果超过某个时间就放弃获取锁。
3、死锁检测:按照线程间获取锁的关系检测线程之间是否发生死锁,如果发生死锁就执行一定的策略,如终断线程或回滚操作等。
2、使用top -Hp 29938 查看进程里面占用资源最多的线程。
[root@localhost opt]# top -Hp 29938 top - 16:25:22 up 51 days, 20:52, 6 users, load average: 2.13, 2.53, 2.78 Threads: 101 total, 1 running, 100 sleeping, 0 stopped, 0 zombie %Cpu(s): 9.2 us, 1.0 sy, 0.0 ni, 89.6 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st KiB Mem : 23083337+total, 12591091+free, 95194368 used, 9728104 buff/cache KiB Swap: 4194300 total, 4194300 free, 0 used. 13460681+avail Mem Unknown command - try 'h' for help PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 31201 root 20 0 18.6g 2.4g 13828 R 99.0 1.1 108:04.58 java 29945 root 20 0 18.6g 2.4g 13828 S 0.7 1.1 0:32.57 java 29950 root 20 0 18.6g 2.4g 13828 S 0.7 1.1 0:32.50 java 29954 root 20 0 18.6g 2.4g 13828 S 0.7 1.1 0:32.57 java 29955 root 20 0 18.6g 2.4g 13828 S 0.7 1.1 0:32.54 java 29958 root 20 0 18.6g 2.4g 13828 S 0.7 1.1 0:32.56 java 29960 root 20 0 18.6g 2.4g 13828 S 0.7 1.1 0:32.56 java ........
此时我们可以看到占用资源最多的线程是:31201。
3、然后使用printf "%x\n" 31201 把线程pid转换成16进制数,就得到了:79e1
[root@localhost opt]# printf "%x\n" 31201 79e1
4、使用jstack 29938 | grep -20 79e1命令查询该线程阻塞的地方。(其中的20表示20行)
然后追溯跟踪到的信息 ,然后根据提示去排查产生死锁的原因。