常用命令
jps 虚拟机进程状况工具
- 格式: jps [option] [hostid]
- option选项
- 实例
jinfo java配置信息工具
- 格式:jinfo [option] pid
jmap java内存映像工具
- 格式: jmap [option] vmid
- 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量
jmap -dump 堆内存dump。还可以通过配置-XX:+HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath分别设置内存溢出时自动创建dump文件和保存dump文件的路径
- 可以看到eur.hprof文件已经生成,我们可以用jvm自带的jvisualvm(在终端输入jvisualvm)来查看这个文件。
jhsdb jmap --heap --pid 17255 堆信息
jstack java堆栈跟踪工具
- 格式:jstack [option] vmid
- 创建死锁代码
public class DeadLock {
private static Object object1 = new Object();
private static Object object2 = new Object();
public static void main(String[] args) {
new Thread(()->{
synchronized (object1){
try {
System.out.println("thread1 start");
Thread.sleep(5000);
}catch (InterruptedException e){
}
synchronized (object2){
System.out.println("thread1 end");
}
}
}).start();
new Thread(()->{
synchronized (object2){
try {
System.out.println("thread2 start");
Thread.sleep(5000);
}catch (InterruptedException e){
}
synchronized (object1){
System.out.println("thread2 end");
}
}
}).start();
System.out.println("main end");
}
}
- 运行结果
- jstack 4992
Java stack information for the threads listed above:
===================================================
"Thread-1":
at DeadLock.lambda$main$1(DeadLock.java:33)
- waiting to lock <0x000000076ac1c628> (a java.lang.Object)
- locked <0x000000076ac1c638> (a java.lang.Object)
at DeadLock$$Lambda$2/764977973.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0":
at DeadLock.lambda$main$0(DeadLock.java:19)
- waiting to lock <0x000000076ac1c638> (a java.lang.Object)
- locked <0x000000076ac1c628> (a java.lang.Object)
at DeadLock$$Lambda$1/1452126962.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
- jvisualvm也能自动检查死锁
用jstack找占用cpu高的线程步骤:
- top找出高cpu的pid
- top -p [pid]
- 按H展示所有线程,找出高cpu的线程tid后,将其转化成十六进制(小写)
- 用jstack pid|grep -A 10 tid可以得到线程堆栈信息,找出对应代码
jstat 虚拟机统计信息监视工具
- 格式:jstat [option vmid [interval [s|ms] [count]]]
如果有很多java进程在跑,可以使用 ps -ef|grep java 来找出各自对应的pid
比较常用的是jstat -gc pid
- S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
- S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
- S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
- S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
- EC:年轻代中Eden(伊甸园)的容量 (字节)
- EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
- OC:Old代的容量 (字节)
- OU:Old代目前已使用空间 (字节)
- MC:方法区(持久代)的容量 (字节)
- MU:方法区(持久代)目前已使用空间 (字节)
- YGC:从应用程序启动到采样时年轻代中gc次数
- YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
- FGC:从应用程序启动到采样时old代(全gc)gc次数
- FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
- GCT:从应用程序启动到采样时gc用的总时间(s)
通过这些数据,可以先给系统设置一些初始性的JVM参数,比如堆内存大小,年轻代大小Eden和Survivor的比例,老年代的大小,大对象的國值,大龄对象进入老年代的阈值等。然后利用优化思路来处理一些问题。
年轻代对象增长的速率
可以执行命令 jstat -gc pid 1000 10(每隔1秒执行1次命令,共执行10次),通过eden区的使用量来估算每秒eden大概新增多少对象,如果系统负载不高,可以把频率1秒换成60秒,甚至更长来观察。需要注意的是,系统可能会有日常期和高峰期,因此需要在不同的时间分别估算不同情况下对象增长速率
Young GC的触发频率和每次用时
知道年轻代对象增长速率我们就能推根据eden区的大小推算出Young GC大概多久触发一次,Young GC的平均耗时可以通过 YGCT/GC 公式算出,根据结果我们大概就能知道系统大概多久会因为Young GC的执行而卡顿多久。
每次Young GC后有多少对象存活和进入老年代
这个因为之前已经大概知道Young GC的频率,假设是每5分钟一次,那么可以执行命令 jstat -gc pid 300000 10,观察每次结果eden,survivor和老年代使用的变化情况,在每次gc后eden区使用一般会大幅减少,survivor和老年代都有可能增长,这些增长的对象就是每次Young GC后存活的对象,同时还可以看出每次Young GC后进去老年代大概多少对象,人而可以推算出老年代对象增长速率.
Full GC的触发频率和每次耗时
知道了老年代对象的增长速率就可以推算出Full GC的触发频率了,Full GC的每次耗时可以用公式 FGCT/FGC 计算得出。 优化思路其实简单来说就是尽量让每次Young GC后的存活对象小于Survivor区域的50%,都留存在年轻代里。尽量别让对象进入老年代。尽量减少Full GC的频率,避免频繁Full GC对JVM性能的影响
当发生老年代空间担保机制时,会频繁的发生Full GC
Arthas
Arthas 是Alibaba开源的Java诊断工具。
- 下载后直接用java -jar运行即可,Arthas会把当前正在运行的java程序列出来。
- 输入dashboard,按
回车/enter,会展示当前进程的信息,按ctrl+c可以中断执行。
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
- 具体使用方法看Arthas文档即可,这里就不再详细说明。
- 文档地址:arthas.aliyun.com/doc/quick-s…