JVM性能监控、故障处理调优工具

208 阅读5分钟

常用命令

jps 虚拟机进程状况工具

  • 格式: jps [option] [hostid]
  • option选项 image.png
  • 实例 image.png

jinfo java配置信息工具

  • 格式:jinfo [option] pid

jmap java内存映像工具

  • 格式: jmap [option] vmid
  • 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量

jmap -dump 堆内存dump。还可以通过配置-XX:+HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath分别设置内存溢出时自动创建dump文件和保存dump文件的路径

image.png

  • 可以看到eur.hprof文件已经生成,我们可以用jvm自带的jvisualvm(在终端输入jvisualvm)来查看这个文件。

image.png

jhsdb jmap --heap --pid 17255 堆信息

image.png

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");
    }
}
  • 运行结果 image.png
  • 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也能自动检查死锁

image.png

用jstack找占用cpu高的线程步骤:

  1. top找出高cpu的pid
  2. top -p [pid]
  3. 按H展示所有线程,找出高cpu的线程tid后,将其转化成十六进制(小写)
  4. 用jstack pid|grep -A 10 tid可以得到线程堆栈信息,找出对应代码

jstat 虚拟机统计信息监视工具

  • 格式:jstat [option vmid [interval [s|ms] [count]]]

如果有很多java进程在跑,可以使用 ps -ef|grep java 来找出各自对应的pid

比较常用的是jstat -gc pid

image.png

  • 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