java应用运行过程中难免会出现问题,特别是在生产环境,发生异常或宕机情况,需要诊断与分析,定位原因,进行优化,避免下次再次出现问题。
虽然现在有很多可视化工具,使用起来比命令行更方便,但我们仍需要对基本的命令进行必要的了解。实际上,可视化工具,往往是基于这些基本命令,拿到数据后进行综合处理后输出的最终结果。
今天从实战角度出发,介绍jps、jmap、jstack和jstat这四个命令的常用方式。
jps
作用:获取java进程号,是后续命令的基础。
当一台服务器运行多个java进程时,该命令默认只输出进程号和应用名,可能无法区分哪个是自己需要分析的对象,这时候可以附加参数 -l,显示完整路径。此外,附加参数-v,可显示jvm参数。
D:\jdk1.7.0_79\bin>jps
3824 Jps
3832 Bootstrap
D:\jdk1.7.0_79\bin>jps -l
3832 org.apache.catalina.startup.Bootstrap
3820 sun.tools.jps.Jps
D:\jdk1.7.0_79\bin>jps -v
1580 Jps -Dapplication.home=D:\jdk1.7.0_79 -Xms8m
3832 Bootstrap -Djava.util.logging.config.file=D:\MessageCenter\tomcat7\conf\log
ging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManage
r -Xms1024m -Xmx2048m -Djdk.tls.ephemeralDHKeySize=2048 -Dignore.endorsed.dirs=
-Dcatalina.base=D:\MessageCenter\tomcat7 -Dcatalina.home=D:\MessageCenter\tomcat
7 -Djava.io.tmpdir=D:\MessageCenter\tomcat7\temp
问题:无效命令
原因:没有配置环境变量
解决:配置环境变量,或者到jdk对应目录bin下打开命令窗口
问题:windows环境下java进程存在,但执行jps无结果
原因:windows权限问题,在 Windows系统中,每个 java 进程启动之后都在 %TMP%/hsperfdata_${user}
(${user}为当前登录用户名) 目录下建立一个以该 java 进程 pid 为文件名的文件,用以记录该 java 进程的一些信息。 通常是因为没有对这个文件的读写权限而导致jps命令查看不到进程。
解决:给当前操作系统用户,设置足够权限,注意,有时候需要重启操作系统才会令权限生效。
jmap
获取java进程内存情况。
常用命令:jmap -heap [进程ID]
作用:显示堆信息
D:\jdk1.7.0_79\bin>jmap -heap 3832
Attaching to process ID 3832, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.79-b02
using thread-local object allocation.
Parallel GC with 2 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 1310720 (1.25MB)
MaxNewSize = 17592186044415 MB
OldSize = 5439488 (5.1875MB)
NewRatio = 2
SurvivorRatio = 8
PermSize = 21757952 (20.75MB)
MaxPermSize = 85983232 (82.0MB)
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 268959744 (256.5MB)
used = 38999632 (37.19294738769531MB)
free = 229960112 (219.3070526123047MB)
14.500174420154117% used
From Space:
capacity = 44564480 (42.5MB)
used = 40604768 (38.723724365234375MB)
free = 3959712 (3.776275634765625MB)
91.11464556525735% used
To Space:
capacity = 44564480 (42.5MB)
used = 0 (0.0MB)
free = 44564480 (42.5MB)
0.0% used
PS Old Generation
capacity = 716177408 (683.0MB)
used = 8192 (0.0078125MB)
free = 716169216 (682.9921875MB)
0.0011438506588579795% used
PS Perm Generation
capacity = 22544384 (21.5MB)
used = 22498624 (21.45635986328125MB)
free = 45760 (0.04364013671875MB)
99.7970226199128% used
15643 interned Strings occupying 1319328 bytes.
常用命令:jmap -histo [进程ID]
作用:按类型显示实例个数及占用空间,可用于排查异常情况,如内存泄露引发的大量对象占用内存不释放。
四列含义依次是序号、实例数量、占用空间、对应类名,注意如下特殊标记代表含义
[C is a char[],[S is a short[],[I is a int[],[B is a byte[],[[I is a int[][]
常用命令:jmap -dump:format=b,file=20230214.dump [进程ID]
作用:生成堆的dump文件,用于内存使用情况进一步分析,通常会辅助以dump文件分析工具。
jstack
查看线程情况。
常用命令:jstack [进程ID]
作用:显示堆栈信息,通常用于查看是否存在死锁。
结合其他命令,找出占用cpu最高的堆栈信息(以下步骤仅适用于linux)
1.使用命令top -p [进程ID] ,显示你的java进程的内存情况,比如3832
2.按H,获取每个线程的内存情况
3.找到内存和cpu占用最高的线程tid,比如4977
4.转为十六进制得到 0x1371
5.执行jstack 3832| grep -A 10 1371,得到线程堆栈信息中1371这个线程所在行的后面10行
6.查看对应的堆栈信息找出可能存在问题的代码
jstat
jstat命令可以查看堆内存各部分的使用量,以及加载类的数量。
jstat [-命令选项] [进程ID] [间隔时间(毫秒)] [查询次数]
常用命令: jstat -gc pid [interval] [count]
作用:垃圾回收统计
该命令是按容量显示,切换成百分比则更直观,命令如下:jstat -gcuitl pid [interval] [count]
使用该命令,可查看新生代(伊甸园、两个幸存区)、老年代的内存使用情况,垃圾回收频率。