Linux - java 分析(jps、Jstat 、jstack\pstack、jmap、jhat)
1、jps(Java Virtual Machine Process Status Tool)
jps主要用来输出JVM中运行的进程状态信息。语法格式如下:
jps [options] [hostid]
如果不指定hostid就默认为当前主机或服务器。
命令行参数选项说明如下:
-q 不输出类名、Jar名和传入main方法的参数
-m 输出传入main方法的参数
-l 输出main类或Jar的全限名
-v 输出传入JVM的参数
例如:jps -ml
再sudo -u hive /usr/java/latest/bin/jstack 19661(此为进程号) > /tmp/jstack.txt
2、Jstat (JVM统计监测工具)
语法格式如下:
jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]
例如:jstat -gcutil pid 5s(每隔5s监控一次内存回收情况)
E 代表 Eden 区使用率;
O(Old)代表老年代使用率 ;
P(Permanent)代表永久代使用率;
CCS 压缩使用比例
M 元空间(MetaspaceSize)已使用的占当前容量百分比
YGC(Young GC)代表Minor GC 次数;
YGCT代表Minor GC耗时;
FGC(Full GC)代表Full GC次数;
FGCT(Full GC)代表Full GC耗时;
GCT代表Minor & Full GC共计耗时。
3、jstack -F pid 检查是否有死锁
jstack主要用来查看某个Java进程内的线程堆栈信息。语法格式如下:
jstack [option] pid
jstack [option] executable core
jstack [option] [[email protected]]remote-hostname-or-ip
命令行参数选项说明如下:
-l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况
-m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)
jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps、top、printf、jstack、grep。
(一):top 查看目前系统中cpu占用最高的进程是什么
(二):top -H -p pid (查看改进程中那个线程的cpu占用率最高)
(三) :printf "%x\n" 4922
- jstack -2617 | grep 133a
发现打印不出来任何结果
- pstack 进程号
- 发现是引入的第三方so包导致。
(注:pstack是一个shell脚本,用于打印正在运行的进程的栈跟踪信息,它实际上是gstack的一个链接,而gstack本身是基于gdb封装的shell脚本.。此命令可显示每个进程的栈跟踪。pstack 命令必须由相应进程的属主或 root 运行。可以使用 pstack 来确定进程挂起的位置。此命令允许使用的唯一选项是要检查的进程的 PID。
与jstack功相比, 它能对潜在的死锁予以提示, 而pstack只提供了线索, 需要gdb进一步的确定。
pstack是gdb的一部分,如果系统没有pstack命令,使用yum搜索安装gdb即可。
这个命令在排查进程问题时非常有用,比如我们发现一个服务一直处于work状态(如假死状态,好似死循环),使用这个命令就能轻松定位问题所在;可以在一段时间内,多执行几次pstack,若发现代码栈总是停在同一个位置,那个位置就需要重点关注,很可能就是出问题的地方)
4、jmap(Memory Map)和jhat(Java Heap Analysis Tool)
jmap用来查看堆内存使用状况,一般结合jhat使用。
jmap语法格式如下:
jmap [option] pid
jmap [option] executable core
jmap [option] [[email protected]]remote-hostname-or-ip
如果运行在64位JVM上,可能需要指定-J-d64命令选项参数。
jmap -permstat pid
使用jmap -heap pid查看进程堆内存使用情况,包括使用的GC算法、堆配置参数和各代中堆内存使用情况。
使用jmap -histo[:live] pid查看堆内存中的对象数目、大小统计直方图,如果带上live则只统计活对象
class name是对象类型,说明如下:
B byte
C char
D double
F float
I int
J long
Z boolean
[ 数组,如[I表示int[]
[L+类名 其他对象
还有一个很常用的情况是:用jmap把进程内存使用情况dump到文件中,再用jhat分析查看。jmap进行dump命令格式如下:
jmap -dump:format=b,file=/opt/logs/dump.dat 2617
dump出来的文件可以用MAT、VisualVM等工具查看,这里用jhat查看:
jhat -port 2617 /opt/logs/dump.dat
打开网页
- jstack信息分析
各状态说明:
New: 当线程对象创建时存在的状态,此时线程不可能执行;
Runnable:当调用thread.start()后,线程变成为Runnable状态。只要得到CPU,就可以执行;
Running:线程正在执行;
Waiting:执行thread.join()或在锁对象调用obj.wait()等情况就会进该状态,表明线程正处于等待某个资源或条件发生来唤醒自己;
Timed_Waiting:执行Thread.sleep(long)、thread.join(long)或obj.wait(long)等就会进该状态,与Waiting的区别在于Timed_Waiting的等待有时间限制;
Blocked:如果进入同步方法或同步代码块,没有获取到锁,则会进入该状态;
Dead:线程执行完毕,或者抛出了未捕获的异常之后,会进入dead状态,表示该线程结束
其次,对于jstack日志,我们要着重关注如下关键信息
Deadlock:表示有死锁
Waiting on condition:等待某个资源或条件发生来唤醒自己。具体需要结合jstacktrace来分析,比如线程正在sleep,网络读写繁忙而等待
Blocked:阻塞
Waiting on monitor entry:在等待获取锁
in Object.wait():获取锁后又执行obj.wait()放弃锁
对于Waiting on monitor entry 和 in Object.wait()的详细描述:Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。从下图中可以看出,每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 "Active Thread",而其它线程都是 "Waiting Thread",分别在两个队列 " Entry Set"和 "Wait Set"里面等候。在 "Entry Set"中等待的线程状态是 "Waiting for monitor entry",而在 "Wait Set"中等待的线程状态是 "in Object.wait()"
6、总结:
对于jstack日志,我们要着重关注如下关键信息
Deadlock:表示有死锁
Waiting on condition:等待某个资源或条件发生来唤醒自己。具体需要结合jstacktrace来分析,比如线程正在sleep,网络读写繁忙而等待
Blocked:阻塞
Waiting on monitor entry:在等待获取锁
如果说系统慢,那么要特别关注Blocked,Waiting on condition
如果说系统的cpu耗的高,那么肯定是线程执行有死循环,那么此时要关注下Runable状态